#!/usr/bin/env bash # ============================================================================== # GoodGo Platform — VPS Server Setup Script # Target: VelikSV01 (185.225.232.65) — Ubuntu 22.04+ # # Usage: # scp infra/server-setup.sh ubuntu@185.225.232.65:~/ # ssh ubuntu@185.225.232.65 'chmod +x ~/server-setup.sh && sudo ~/server-setup.sh' # ============================================================================== set -euo pipefail # ── Colors ──────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log() { echo -e "${GREEN}[SETUP]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } err() { echo -e "${RED}[ERROR]${NC} $*" >&2; } # ── Pre-flight checks ──────────────────────────────────────────────────────── if [ "$(id -u)" -ne 0 ]; then err "This script must be run as root (sudo)." exit 1 fi DEPLOY_USER="${DEPLOY_USER:-ubuntu}" DEPLOY_DIR="/home/${DEPLOY_USER}/goodgo" log "Starting GoodGo Platform server setup..." log "Deploy user: ${DEPLOY_USER}" log "Deploy dir: ${DEPLOY_DIR}" # ── 1. System Updates ───────────────────────────────────────────────────────── log "Updating system packages..." apt-get update -qq apt-get upgrade -y -qq # ── 2. Install Essential Packages ───────────────────────────────────────────── log "Installing essential packages..." apt-get install -y -qq \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release \ software-properties-common \ git \ jq \ htop \ unzip \ fail2ban \ ufw \ logrotate # ── 3. Install Docker Engine ───────────────────────────────────────────────── if command -v docker &>/dev/null; then log "Docker already installed: $(docker --version)" else log "Installing Docker Engine..." curl -fsSL https://get.docker.com | sh # Add deploy user to docker group usermod -aG docker "${DEPLOY_USER}" log "Docker installed: $(docker --version)" fi # Ensure Docker starts on boot systemctl enable docker systemctl start docker # ── 4. Install Docker Compose v2 (plugin) ──────────────────────────────────── if docker compose version &>/dev/null; then log "Docker Compose already installed: $(docker compose version --short)" else log "Installing Docker Compose v2 plugin..." DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r .tag_name) mkdir -p /usr/local/lib/docker/cli-plugins curl -fsSL "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-$(uname -m)" \ -o /usr/local/lib/docker/cli-plugins/docker-compose chmod +x /usr/local/lib/docker/cli-plugins/docker-compose log "Docker Compose installed: $(docker compose version --short)" fi # ── 5. Install Nginx ────────────────────────────────────────────────────────── if command -v nginx &>/dev/null; then log "Nginx already installed: $(nginx -v 2>&1)" else log "Installing Nginx..." apt-get install -y -qq nginx log "Nginx installed: $(nginx -v 2>&1)" fi systemctl enable nginx systemctl start nginx # ── 6. Configure Firewall (ufw) ────────────────────────────────────────────── log "Configuring firewall (ufw)..." ufw --force reset ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp comment 'SSH' ufw allow 80/tcp comment 'HTTP — redirect to HTTPS' ufw allow 443/tcp comment 'HTTPS' ufw --force enable log "Firewall configured. Active rules:" ufw status verbose # ── 7. Configure fail2ban ───────────────────────────────────────────────────── log "Configuring fail2ban..." cat > /etc/fail2ban/jail.local << 'F2B_CONF' [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true port = ssh logpath = %(sshd_log)s maxretry = 3 [nginx-http-auth] enabled = true [nginx-botsearch] enabled = true F2B_CONF systemctl enable fail2ban systemctl restart fail2ban log "fail2ban configured and running." # ── 8. Create Directory Structure ──────────────────────────────────────────── log "Creating deployment directory structure..." mkdir -p "${DEPLOY_DIR}"/{monitoring/{prometheus,grafana/{provisioning,dashboards},loki,promtail,alertmanager},scripts/backup,infra/pgbouncer} chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${DEPLOY_DIR}" log "Directory structure created at ${DEPLOY_DIR}" # ── 9. Create SSL Directory ────────────────────────────────────────────────── log "Creating SSL certificate directory..." mkdir -p /etc/ssl/goodgo chmod 700 /etc/ssl/goodgo log "SSL directory: /etc/ssl/goodgo (place origin.pem + origin-key.pem here)" # ── 10. Nginx Base Configuration ───────────────────────────────────────────── log "Creating Nginx base configuration..." # Create sites-available/sites-enabled structure if not exists mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled # Check if nginx.conf already includes sites-enabled if ! grep -q 'sites-enabled' /etc/nginx/nginx.conf; then warn "Adding 'include sites-enabled' to nginx.conf" sed -i '/http {/a \ include /etc/nginx/sites-enabled/*;' /etc/nginx/nginx.conf fi # Remove default site rm -f /etc/nginx/sites-enabled/default # Nginx performance tuning cat > /etc/nginx/conf.d/performance.conf << 'NGINX_PERF' # GoodGo Platform — Nginx Performance Tuning # Rate limiting zone (used by API vhost) limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s; # Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; # Proxy settings proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffers 32 8k; # Security server_tokens off; NGINX_PERF nginx -t && systemctl reload nginx log "Nginx base configuration ready." # ── 11. Docker Log Rotation ────────────────────────────────────────────────── log "Configuring Docker log rotation..." mkdir -p /etc/docker cat > /etc/docker/daemon.json << 'DOCKER_LOG' { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "5" }, "storage-driver": "overlay2" } DOCKER_LOG systemctl restart docker log "Docker log rotation configured." # ── 12. Swap (if <4GB RAM) ─────────────────────────────────────────────────── TOTAL_MEM=$(free -m | awk '/^Mem:/{print $2}') if [ "$TOTAL_MEM" -lt 4096 ]; then if [ ! -f /swapfile ]; then log "Low RAM (${TOTAL_MEM}MB). Creating 4GB swap..." fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab log "Swap created and enabled." else log "Swap already exists." fi else log "RAM: ${TOTAL_MEM}MB — swap not needed." fi # ── 13. Kernel Tuning (for Docker/PostgreSQL) ──────────────────────────────── log "Applying kernel tuning..." cat >> /etc/sysctl.conf << 'SYSCTL' # GoodGo — Docker + PostgreSQL tuning vm.overcommit_memory = 1 vm.swappiness = 10 net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 net.ipv4.ip_local_port_range = 1024 65535 fs.file-max = 2097152 SYSCTL sysctl -p >/dev/null 2>&1 || true log "Kernel parameters tuned." # ── Summary ────────────────────────────────────────────────────────────────── echo "" log "==========================================" log " Server setup complete!" log "==========================================" log "" log " Next steps:" log " 1. Place Cloudflare Origin Certificate:" log " /etc/ssl/goodgo/origin.pem" log " /etc/ssl/goodgo/origin-key.pem" log "" log " 2. Copy Nginx vhost configs to:" log " /etc/nginx/sites-available/" log " Then symlink to /etc/nginx/sites-enabled/" log "" log " 3. Create .env file at:" log " ${DEPLOY_DIR}/.env" log "" log " 4. Login to GHCR:" log " docker login ghcr.io" log "" log " 5. Deploy:" log " cd ${DEPLOY_DIR}" log " docker compose -f docker-compose.prod.yml up -d" log "=========================================="