-
-
Save arpee/22cec55b8e74c09c2e17e5a42eead6cf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Saito Node Setup Script for Ubuntu | |
| # This script installs dependencies, sets up Saito node, configures nginx with SSL | |
| set -e # Exit on any error | |
| # Color codes for output | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| BLUE='\033[0;34m' | |
| NC='\033[0m' # No Color | |
| # Function to print colored output | |
| print_status() { | |
| echo -e "${BLUE}[INFO]${NC} $1" | |
| } | |
| print_success() { | |
| echo -e "${GREEN}[SUCCESS]${NC} $1" | |
| } | |
| print_warning() { | |
| echo -e "${YELLOW}[WARNING]${NC} $1" | |
| } | |
| print_error() { | |
| echo -e "${RED}[ERROR]${NC} $1" | |
| } | |
| # Check if running as root | |
| if [ "$EUID" -ne 0 ]; then | |
| print_error "This script must be run as root (use sudo)" | |
| exit 1 | |
| fi | |
| # Display warning and confirmation | |
| echo "" | |
| print_warning "==========================================" | |
| print_warning " SAITO WEB NODE PROVISIONING SCRIPT" | |
| print_warning "==========================================" | |
| echo "" | |
| print_error "WARNING: This script will provision a complete Saito Web Node" | |
| echo "" | |
| print_status "This script is designed for:" | |
| echo "• Fresh installation of Ubuntu 24.04 LTS" | |
| echo "• Setting up a new Saito Web Node from scratch" | |
| echo "" | |
| print_status "What will be installed/configured:" | |
| echo "• System packages: git, g++, make, python3, Node.js, TypeScript" | |
| echo "• Web server: nginx with SSL/TLS (Let's Encrypt)" | |
| echo "• Process manager: PM2 for service management" | |
| echo "• Saito blockchain node software" | |
| echo "" | |
| print_error "IMPORTANT WARNINGS:" | |
| echo "• This will OVERWRITE any existing Saito installation in /opt/saito" | |
| echo "• This will OVERWRITE nginx configurations for your domain" | |
| echo "• This assumes a clean Ubuntu 24.04 system" | |
| echo "• Your domain must point to this server's IP address" | |
| echo "" | |
| print_warning "If you have an existing Saito installation or custom nginx configs," | |
| print_warning "they will be replaced. Make backups if needed!" | |
| echo "" | |
| # Confirmation prompt | |
| while true; do | |
| read -p "Do you want to continue with the installation? (yes/no): " yn | |
| case $yn in | |
| [Yy]es ) break;; | |
| [Nn]o ) print_status "Installation cancelled."; exit 0;; | |
| * ) echo "Please answer yes or no.";; | |
| esac | |
| done | |
| print_status "Starting Saito Node setup for Ubuntu..." | |
| # Prompt for TLD early in the process | |
| print_status "Domain configuration required..." | |
| while true; do | |
| read -p "Enter your domain name (e.g., example.com, sub.example.com, api.v1.example.com): " TLD | |
| # Enhanced regex to allow subdomains of any depth | |
| if [[ $TLD =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ ]]; then | |
| print_success "Domain configured: $TLD" | |
| break | |
| else | |
| print_error "Please enter a valid domain name (supports subdomains like sub.example.com or api.v1.example.com)" | |
| fi | |
| done | |
| print_status "Proceeding with installation for domain: $TLD" | |
| # Get server's public IP | |
| print_status "Testing domain configuration..." | |
| echo "Getting server's public IP address..." | |
| # Try multiple methods to get public IP | |
| SERVER_IP="" | |
| for method in "curl -s ifconfig.me" "curl -s ipecho.net/plain" "dig +short myip.opendns.com @resolver1.opendns.com" "curl -s icanhazip.com"; do | |
| if SERVER_IP=$(eval $method 2>/dev/null) && [[ $SERVER_IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then | |
| break | |
| fi | |
| done | |
| if [ -z "$SERVER_IP" ]; then | |
| print_error "Could not determine server's public IP address" | |
| print_warning "Please ensure your server has internet connectivity" | |
| exit 1 | |
| fi | |
| print_success "Server public IP: $SERVER_IP" | |
| # Test domain resolution | |
| print_status "Testing if $TLD resolves to this server..." | |
| # Try to resolve the domain | |
| DOMAIN_IP="" | |
| if command -v dig &> /dev/null; then | |
| DOMAIN_IP=$(dig +short "$TLD" A | tail -n1) | |
| elif command -v nslookup &> /dev/null; then | |
| DOMAIN_IP=$(nslookup "$TLD" | grep -A1 "Name:" | tail -n1 | awk '{print $2}' 2>/dev/null) | |
| fi | |
| if [ -z "$DOMAIN_IP" ]; then | |
| print_error "Could not resolve domain $TLD" | |
| DOMAIN_TEST_FAILED=true | |
| elif [ "$DOMAIN_IP" = "$SERVER_IP" ]; then | |
| print_success "✅ Domain test passed! $TLD resolves to $SERVER_IP" | |
| DOMAIN_TEST_FAILED=false | |
| else | |
| print_error "❌ Domain test failed!" | |
| print_error " Domain $TLD resolves to: $DOMAIN_IP" | |
| print_error " Server IP is: $SERVER_IP" | |
| print_error " These don't match!" | |
| DOMAIN_TEST_FAILED=true | |
| fi | |
| # Handle domain test results | |
| if [ "$DOMAIN_TEST_FAILED" = true ]; then | |
| echo "" | |
| print_warning "Your domain is not properly configured!" | |
| print_status "To fix this, you need to:" | |
| echo "1. Log into your domain registrar or DNS provider" | |
| echo "2. Create an A record pointing $TLD to $SERVER_IP" | |
| echo "3. Wait for DNS propagation (can take 5-60 minutes)" | |
| echo "" | |
| while true; do | |
| echo "Options:" | |
| echo "1. Continue anyway (SSL setup will fail, site will be HTTP-only)" | |
| echo "2. Pause here while you configure DNS" | |
| echo "3. Exit and run script later" | |
| read -p "Choose option (1/2/3): " choice | |
| case $choice in | |
| 1) | |
| print_warning "Continuing without proper DNS configuration" | |
| print_warning "SSL certificate setup will fail" | |
| print_warning "Your site will only work over HTTP (unsecured)" | |
| print_warning "Many modern web features require HTTPS and won't work!" | |
| print_warning "Users may see security warnings in their browsers" | |
| echo "" | |
| read -p "Are you sure you want to continue? (yes/no): " confirm | |
| if [[ $confirm =~ ^[Yy]es$ ]]; then | |
| SKIP_SSL=true | |
| break | |
| fi | |
| ;; | |
| 2) | |
| print_status "Script paused. Configure your DNS then press Enter to test again..." | |
| read -p "Press Enter when ready to test DNS again, or Ctrl+C to abort: " | |
| # Re-test domain resolution | |
| print_status "Re-testing domain resolution..." | |
| if command -v dig &> /dev/null; then | |
| DOMAIN_IP=$(dig +short "$TLD" A | tail -n1) | |
| elif command -v nslookup &> /dev/null; then | |
| DOMAIN_IP=$(nslookup "$TLD" | grep -A1 "Name:" | tail -n1 | awk '{print $2}' 2>/dev/null) | |
| fi | |
| if [ "$DOMAIN_IP" = "$SERVER_IP" ]; then | |
| print_success "Domain now resolves correctly!" | |
| DOMAIN_TEST_FAILED=false | |
| break | |
| else | |
| print_error "Domain still not resolving correctly" | |
| print_error "Current resolution: $DOMAIN_IP (expected: $SERVER_IP)" | |
| fi | |
| ;; | |
| 3) | |
| print_status "Installation cancelled." | |
| print_warning "Remember: SSL certificates are required for:" | |
| print_warning "• Secure data transmission" | |
| print_warning "• Modern browser features (geolocation, camera, etc.)" | |
| print_warning "• Service workers and PWA functionality" | |
| print_warning "• Protection against man-in-the-middle attacks" | |
| print_warning "• User trust and search engine rankings" | |
| exit 0 | |
| ;; | |
| *) | |
| echo "Please choose 1, 2, or 3." | |
| ;; | |
| esac | |
| done | |
| fi | |
| echo "" | |
| # Update package list | |
| print_status "Updating package list..." | |
| apt update | |
| # Install basic dependencies if they don't exist | |
| print_status "Installing basic dependencies..." | |
| # Check and install git | |
| if ! command -v git &> /dev/null; then | |
| print_status "Installing git..." | |
| apt install -y git | |
| else | |
| print_success "git is already installed" | |
| fi | |
| # Check and install g++ | |
| if ! command -v g++ &> /dev/null; then | |
| print_status "Installing g++..." | |
| apt install -y g++ | |
| else | |
| print_success "g++ is already installed" | |
| fi | |
| # Check and install make | |
| if ! command -v make &> /dev/null; then | |
| print_status "Installing make..." | |
| apt install -y make | |
| else | |
| print_success "make is already installed" | |
| fi | |
| # Check and install python3 | |
| if ! command -v python3 &> /dev/null; then | |
| print_status "Installing python3..." | |
| apt install -y python3 python3-pip | |
| else | |
| print_success "python3 is already installed" | |
| fi | |
| # Install Node.js and npm (required for tsc and pm2) | |
| if ! command -v node &> /dev/null; then | |
| print_status "Installing Node.js..." | |
| curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - | |
| apt install -y nodejs | |
| else | |
| print_success "Node.js is already installed" | |
| fi | |
| # Check and install TypeScript compiler | |
| if ! command -v tsc &> /dev/null; then | |
| print_status "Installing TypeScript..." | |
| npm install -g typescript | |
| else | |
| print_success "TypeScript is already installed" | |
| fi | |
| # Install nginx | |
| print_status "Installing nginx..." | |
| apt install -y nginx | |
| # Install pm2 | |
| if ! command -v pm2 &> /dev/null; then | |
| print_status "Installing pm2..." | |
| npm install -g pm2 | |
| else | |
| print_success "pm2 is already installed" | |
| fi | |
| # Install certbot for Let's Encrypt | |
| print_status "Installing certbot..." | |
| apt install -y certbot python3-certbot-nginx | |
| # Change to /opt directory | |
| print_status "Changing to /opt directory..." | |
| cd /opt | |
| # Clone Saito repository | |
| if [ ! -d "saito" ]; then | |
| print_status "Cloning Saito repository..." | |
| git clone https://github.com/saitotech/saito | |
| git checkout prod | |
| else | |
| print_warning "Saito directory already exists, pulling latest changes..." | |
| cd saito | |
| git checkout prod | |
| git pull | |
| cd /opt | |
| fi | |
| # Install Saito dependencies | |
| print_status "Installing Saito node dependencies..." | |
| cd saito/node | |
| npm install | |
| # Run npm nuke to initialize/reset Saito | |
| print_status "Running npm run nuke to initialize Saito..." | |
| npm run nuke | |
| print_status "Configuring nginx for domain: $TLD" | |
| # Create initial HTTP-only nginx configuration | |
| cat > "/etc/nginx/sites-available/$TLD" << EOF | |
| server { | |
| listen 80; | |
| server_name $TLD www.$TLD; | |
| # Gzip compression | |
| gzip on; | |
| gzip_proxied any; | |
| gzip_min_length 256; | |
| gzip_comp_level 9; | |
| gzip_types | |
| text/plain | |
| text/css | |
| text/xml | |
| text/javascript | |
| application/javascript | |
| application/xml+rss | |
| application/json; | |
| # Proxy timeouts | |
| proxy_connect_timeout 300s; | |
| proxy_send_timeout 300s; | |
| proxy_read_timeout 300s; | |
| # Cache headers (7 days) | |
| location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { | |
| expires 7d; | |
| add_header Cache-Control "public, immutable"; | |
| proxy_pass http://localhost:12101; | |
| proxy_set_header Upgrade \$http_upgrade; | |
| proxy_set_header Connection "upgrade"; | |
| proxy_set_header Host \$host; | |
| proxy_set_header X-Real-IP \$remote_addr; | |
| proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
| proxy_set_header X-Forwarded-Proto \$scheme; | |
| } | |
| # Main location block | |
| location / { | |
| proxy_pass http://localhost:12101; | |
| # Generic headers | |
| proxy_set_header Upgrade \$http_upgrade; | |
| proxy_set_header Connection "upgrade"; | |
| proxy_set_header Host \$host; | |
| proxy_set_header X-Real-IP \$remote_addr; | |
| proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
| proxy_set_header X-Forwarded-Proto \$scheme; | |
| # Additional headers for better proxy handling | |
| proxy_http_version 1.1; | |
| proxy_buffering off; | |
| proxy_request_buffering off; | |
| } | |
| } | |
| EOF | |
| # Enable the site | |
| print_status "Enabling nginx site..." | |
| ln -sf "/etc/nginx/sites-available/$TLD" "/etc/nginx/sites-enabled/$TLD" | |
| # Remove default nginx site if it exists | |
| if [ -f "/etc/nginx/sites-enabled/default" ]; then | |
| rm /etc/nginx/sites-enabled/default | |
| fi | |
| # Test nginx configuration | |
| print_status "Testing nginx configuration..." | |
| if nginx -t; then | |
| print_success "Nginx configuration is valid" | |
| else | |
| print_error "Nginx configuration test failed" | |
| exit 1 | |
| fi | |
| # Start and enable nginx | |
| print_status "Starting nginx..." | |
| systemctl start nginx | |
| systemctl enable nginx | |
| print_status "Obtaining Let's Encrypt SSL certificate..." | |
| # Skip SSL if domain test failed and user chose to continue anyway | |
| if [ "$SKIP_SSL" = true ]; then | |
| print_warning "Skipping SSL certificate setup due to DNS configuration issues" | |
| print_warning "Your site will only be accessible via HTTP" | |
| else | |
| # Obtain SSL certificate | |
| if certbot --nginx -d "$TLD" -d "www.$TLD" --non-interactive --agree-tos --email "admin@$TLD"; then | |
| print_success "SSL certificate obtained successfully" | |
| print_status "Certbot has automatically updated the nginx configuration with SSL and HTTPS redirect" | |
| else | |
| print_warning "SSL certificate creation failed. Site will remain HTTP-only." | |
| print_warning "You can manually run: certbot --nginx -d $TLD -d www.$TLD" | |
| fi | |
| fi | |
| # Restart nginx to apply all changes | |
| print_status "Restarting nginx..." | |
| systemctl restart nginx | |
| # Setup pm2 to auto-start Saito node | |
| print_status "Setting up PM2 for Saito node..." | |
| cd /opt/saito/node | |
| # Create PM2 ecosystem file | |
| cat > ecosystem.config.js << 'EOF' | |
| module.exports = { | |
| apps: [{ | |
| name: 'saito-node', | |
| script: 'npm start', | |
| instances: 1, | |
| exec_mode: 'fork', | |
| watch: false, | |
| max_memory_restart: '2G', | |
| error_file: './logs/err.log', | |
| out_file: './logs/out.log', | |
| log_file: './logs/saito.log', | |
| time: true | |
| }] | |
| }; | |
| EOF | |
| # Create logs directory | |
| mkdir -p logs | |
| # Start Saito with PM2 | |
| print_status "Starting Saito node with PM2..." | |
| pm2 start ecosystem.config.js | |
| pm2 save | |
| pm2 startup systemd -u root --hp /root | |
| print_success "Setup completed successfully!" | |
| echo "" | |
| print_status "Summary:" | |
| echo "• Saito node installed in /opt/saito" | |
| echo "• Nginx configured with SSL for $TLD" | |
| echo "• PM2 managing Saito node process" | |
| echo "• Gzip compression enabled" | |
| echo "• 7-day cache headers for static assets" | |
| echo "• HTTP traffic redirected to HTTPS" | |
| echo "" | |
| print_status "Next steps:" | |
| echo "• Check PM2 status: pm2 status" | |
| echo "• View Saito logs: pm2 logs saito-node" | |
| echo "• Nginx logs: /var/log/nginx/" | |
| echo "" | |
| print_status "IMPORTANT: Please check your Saito installation:" | |
| if [[ $TLD == *"https"* ]] || [ -f "/etc/letsencrypt/live/$TLD/fullchain.pem" ]; then | |
| echo "Visit: https://$TLD/" | |
| else | |
| echo "Visit: http://$TLD/" | |
| fi | |
| echo "" | |
| print_success "You should see a Saito welcome page with setup instructions!" | |
| print_warning "If you don't see the welcome page, check the PM2 logs for any errors." | |
| echo "" | |
| print_warning "Don't forget to configure your firewall to allow ports 80 and 443!" | |
| echo "Example: ufw allow 'Nginx Full'" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment