#!/bin/bash # ============================================================================= # SJDEV.CO SERVER SETUP SCRIPT # ============================================================================= # Target: Ubuntu 24.04.3 LTS on AWS EC2 (18.119.237.252) # # USAGE: # 1. SSH into your server: # ssh -i /Users/kjannette/.ssh/sjdev_forever.pem ubuntu@18.119.237.252 # 2. Upload this script: # scp -i /Users/kjannette/.ssh/sjdev_forever.pem setup-sjdev.sh ubuntu@18.119.237.252:~/ # 3. Run it: # chmod +x ~/setup-sjdev.sh && sudo ~/setup-sjdev.sh # # The script will pause at key checkpoints and print status updates. # ============================================================================= set -e # Exit on error RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_step() { echo -e "\n${GREEN}[STEP]${NC} $1" echo "================================================================" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_ok() { echo -e "${GREEN}[OK]${NC} $1" } # ============================================================================= # STEP 1: System Update # ============================================================================= log_step "1/15 - Updating system packages" apt update && apt upgrade -y log_ok "System updated" # ============================================================================= # STEP 2: Install core packages (NGINX, fail2ban, cmake, build tools) # ============================================================================= log_step "2/15 - Installing core packages" apt install -y nginx fail2ban cmake build-essential git curl wget software-properties-common # Enable and start nginx systemctl enable nginx systemctl start nginx log_ok "Core packages installed" # ============================================================================= # STEP 3: Install Node.js via NVM (for ubuntu user) # ============================================================================= log_step "3/15 - Installing NVM and Node.js" # Install NVM for the ubuntu user export NVM_DIR="/home/ubuntu/.nvm" if [ ! -d "$NVM_DIR" ]; then sudo -u ubuntu bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash' fi # Source NVM and install Node LTS export NVM_DIR="/home/ubuntu/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # If running as root, also install node globally accessible if ! command -v node &> /dev/null; then # Install via NodeSource as fallback for root access curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs fi # Verify node --version && log_ok "Node.js installed: $(node --version)" npm --version && log_ok "npm installed: $(npm --version)" # ============================================================================= # STEP 4: Install cmake (already done in step 2, verify) # ============================================================================= log_step "4/15 - Verifying cmake (needed for FAISS)" cmake --version && log_ok "cmake installed: $(cmake --version | head -1)" # ============================================================================= # STEP 5: Configure GitHub PAT as environment variable # ============================================================================= log_step "5/15 - Configuring GitHub PAT environment variable" # Add to /etc/environment for system-wide persistence if ! grep -q "GH_PAT" /etc/environment 2>/dev/null; then echo 'GH_PAT=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' >> /etc/environment log_ok "GitHub PAT added to /etc/environment" else log_warn "GH_PAT already exists in /etc/environment" fi # Also add to ubuntu user's bashrc if ! grep -q "GH_PAT" /home/ubuntu/.bashrc 2>/dev/null; then echo 'export GH_PAT=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' >> /home/ubuntu/.bashrc log_ok "GitHub PAT added to ubuntu user's .bashrc" fi # Export for current session export GH_PAT=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 # ============================================================================= # STEP 6: Clone repositories into /var # ============================================================================= log_step "6/15 - Cloning repositories into /var" cd /var if [ ! -d "/var/sjdevnext15Backend" ]; then git clone https://kjannette:${GH_PAT}@github.com/kjannette/sjdevnext15Backend.git log_ok "Backend repo cloned" else log_warn "Backend repo already exists, pulling latest" cd /var/sjdevnext15Backend && git pull fi cd /var if [ ! -d "/var/sjdevnext15" ]; then git clone https://kjannette:${GH_PAT}@github.com/kjannette/sjdevnext15.git log_ok "Frontend repo cloned" else log_warn "Frontend repo already exists, pulling latest" cd /var/sjdevnext15 && git pull fi # ============================================================================= # STEP 7: Install frontend dependencies # ============================================================================= log_step "7/15 - Installing frontend dependencies (sjdevnext15)" cd /var/sjdevnext15 npm install log_ok "Frontend dependencies installed" # ============================================================================= # STEP 8: Install backend dependencies # ============================================================================= log_step "8/15 - Installing backend dependencies (sjdevnext15Backend)" cd /var/sjdevnext15Backend npm install log_ok "Backend dependencies installed" # ============================================================================= # STEP 9: Configure NGINX # ============================================================================= log_step "9/15 - Configuring NGINX for sjdev.co" # Remove default site if it exists rm -f /etc/nginx/sites-enabled/default # Write the NGINX config (HTTP-only first; certbot will add SSL) cat > /etc/nginx/sites-available/sjdev.co << 'NGINX_EOF' # NGINX Configuration for sjdev.co # HTTP only initially - certbot will add SSL server { listen 80; listen [::]:80; server_name sjdev.co www.sjdev.co; # Allow Let's Encrypt verification location /.well-known/acme-challenge/ { root /usr/share/nginx/html; } # Root directory for demo apps set $apps_root /var/www/sjdev-demo-apps; # ============================================ # DEMO APPS - Static React Builds # ============================================ location /demos/salesflow { alias /var/salesflow/build/; try_files $uri $uri/ /demos/salesflow/index.html; } location /demos/bookbrowser { alias /var/reactnd-project-bookbrowser/build/; try_files $uri $uri/ /demos/bookbrowser/index.html; } location /demos/budgetize { alias /var/www/sjdev-demo-apps/budgetize; try_files $uri $uri/ /demos/budgetize/index.html; } # ============================================ # BACKEND API PROXY # ============================================ location /v1/ { proxy_pass http://localhost:3001; proxy_http_version 1.1; 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; proxy_cache_bypass $http_upgrade; proxy_read_timeout 300; proxy_connect_timeout 300; } # ============================================ # NEXT.JS APPLICATION # ============================================ location /_next/static { proxy_pass http://localhost:3000; proxy_cache_valid 200 60m; add_header Cache-Control "public, max-age=3600, immutable"; } location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; 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; proxy_cache_bypass $http_upgrade; proxy_read_timeout 300; proxy_connect_timeout 300; } } NGINX_EOF # Create symlink to sites-enabled ln -sf /etc/nginx/sites-available/sjdev.co /etc/nginx/sites-enabled/sjdev.co # Test NGINX config nginx -t && log_ok "NGINX configuration valid" # Reload NGINX systemctl reload nginx log_ok "NGINX configured and reloaded" # ============================================================================= # STEP 10: Install Certbot and obtain SSL # ============================================================================= log_step "10/15 - Installing Certbot and obtaining SSL certificate" # Install certbot apt install -y certbot python3-certbot-nginx # Obtain SSL certificate (will modify NGINX config automatically) certbot --nginx -d sjdev.co -d www.sjdev.co --non-interactive --agree-tos --email admin@sjdev.co --redirect log_ok "SSL certificate obtained and NGINX updated" # ============================================================================= # STEP 11: Configure fail2ban # ============================================================================= log_step "11/15 - Configuring fail2ban" cat > /etc/fail2ban/jail.local << 'F2B_EOF' [DEFAULT] # Ban hosts for 1 hour bantime = 3600 # Find failures within 10 minutes findtime = 600 # Allow 5 retries before ban maxretry = 5 # Use systemd backend backend = systemd # Action: ban via iptables and send no email action = %(action_)s [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 7200 [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 5 [nginx-limit-req] enabled = true port = http,https filter = nginx-limit-req logpath = /var/log/nginx/error.log maxretry = 10 [nginx-botsearch] enabled = true port = http,https filter = nginx-botsearch logpath = /var/log/nginx/access.log maxretry = 2 F2B_EOF systemctl enable fail2ban systemctl restart fail2ban log_ok "fail2ban configured and running" # ============================================================================= # STEP 12: Install PM2 and configure processes # ============================================================================= log_step "12/15 - Installing and configuring PM2" npm install -g pm2 # Read package.json files to determine start scripts # Frontend (Next.js) typically uses 'npm start' or 'next start' on port 3000 # Backend typically uses 'npm start' or 'node server.js' on port 3001 # Start the backend cd /var/sjdevnext15Backend echo "Starting backend..." pm2 start npm --name "sjdev-backend" -- start log_ok "Backend started with PM2" # Build the frontend first (Next.js needs a build step) cd /var/sjdevnext15 echo "Building frontend (this may take a few minutes)..." npm run build 2>&1 || log_warn "Frontend build had warnings - check output above" # Start the frontend pm2 start npm --name "sjdev-frontend" -- start log_ok "Frontend started with PM2" # Save PM2 process list so it restores after reboot pm2 save log_ok "PM2 process list saved" # Configure PM2 startup script (runs on system boot) pm2 startup systemd -u ubuntu --hp /home/ubuntu # The above command outputs a command to run - we execute it automatically env PATH=$PATH:/usr/bin pm2 startup systemd -u ubuntu --hp /home/ubuntu log_ok "PM2 startup configured for system reboot" # ============================================================================= # STEP 13: Disable password authentication for SSH # ============================================================================= log_step "13/15 - Disabling SSH password authentication" # Backup sshd_config cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak # Disable password authentication sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config sed -i 's/^#*ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' /etc/ssh/sshd_config sed -i 's/^#*KbdInteractiveAuthentication.*/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config # Also check sshd_config.d/ directory for overrides if [ -d /etc/ssh/sshd_config.d ]; then for f in /etc/ssh/sshd_config.d/*.conf; do if [ -f "$f" ]; then sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' "$f" fi done fi # Validate and restart SSH sshd -t && systemctl restart sshd log_ok "SSH password authentication disabled" # ============================================================================= # STEP 14: Verify everything is running # ============================================================================= log_step "14/15 - Verification checks" echo "" echo "--- NGINX Status ---" systemctl is-active nginx && log_ok "NGINX is running" || log_error "NGINX is NOT running" echo "" echo "--- fail2ban Status ---" systemctl is-active fail2ban && log_ok "fail2ban is running" || log_error "fail2ban is NOT running" echo "" echo "--- PM2 Process List ---" pm2 list echo "" echo "--- SSL Certificate Status ---" certbot certificates 2>/dev/null || log_warn "Could not check certbot certificates" echo "" echo "--- Testing local connectivity ---" curl -s -o /dev/null -w "Frontend (port 3000): HTTP %{http_code}\n" http://localhost:3000 || log_warn "Frontend not responding on port 3000" curl -s -o /dev/null -w "Backend (port 3001): HTTP %{http_code}\n" http://localhost:3001 || log_warn "Backend not responding on port 3001" echo "" echo "--- Testing external HTTPS ---" curl -s -o /dev/null -w "https://www.sjdev.co: HTTP %{http_code}\n" https://www.sjdev.co || log_warn "HTTPS site not responding externally" # ============================================================================= # STEP 15: Final Report # ============================================================================= log_step "15/15 - SETUP COMPLETE" echo "" echo "==============================================" echo " SJDEV.CO SERVER SETUP - FINAL REPORT" echo "==============================================" echo "" echo " Server: 18.119.237.252 (Ubuntu 24.04)" echo " Domain: https://www.sjdev.co" echo " Frontend: Next.js on port 3000 (PM2: sjdev-frontend)" echo " Backend: Express on port 3001 (PM2: sjdev-backend)" echo " SSL: Let's Encrypt via Certbot" echo " Firewall: fail2ban enabled (SSH, NGINX)" echo " SSH: Key-only authentication" echo " PM2: Auto-restart on crash + system reboot" echo "" echo " IMPORTANT REMINDERS:" echo " 1. REVOKE your GitHub PAT and generate a new one" echo " (it was exposed in the setup conversation)" echo " 2. Check PM2 logs: pm2 logs" echo " 3. Monitor: pm2 monit" echo " 4. Check fail2ban: sudo fail2ban-client status" echo "" echo "=============================================="