# Deployment Guide β€” go-first / URPI This guide covers deploying the go-first application to production at **https://www.urpi.be**. --- ## πŸ—οΈ Architecture Overview ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Users │────▢│ NGINX │────▢│ Go App β”‚ β”‚ (HTTPS) β”‚ β”‚ (SSL/TLS) β”‚ β”‚ (Port 8080)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”‚ PostgreSQL │◀───▢│ Redis β”‚ β”‚ (Port 5432)β”‚ β”‚ (Port 6379)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“‹ Prerequisites ### Server Requirements - **OS**: Ubuntu 22.04+ / Debian 12+ / Alpine Linux - **CPU**: 2+ vCPUs - **RAM**: 4GB+ (2GB minimum for app + DB) - **Disk**: 20GB+ SSD - **Network**: Public IPv4/IPv6, ports 80, 443, 22 ### Software - Docker 24+ & Docker Compose 2+ - Git - Certbot (Let's Encrypt) - (Optional) kubectl for Kubernetes --- ## πŸ”§ Server Setup ### 1. Initial Server Hardening ```bash # Update system sudo apt update && sudo apt upgrade -y # Create deploy user sudo adduser deploy --gecos "" --disabled-password sudo usermod -aG docker deploy sudo usermod -aG sudo deploy # Setup SSH keys (from your local machine) ssh-copy-id deploy@your-server-ip # Configure firewall sudo ufw allow 22/tcp # SSH sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS sudo ufw enable ``` ### 2. Install Docker ```bash # Install Docker curl -fsSL https://get.docker.com | sh # Install Docker Compose sudo apt install -y docker-compose-plugin # Verify docker --version docker compose version ``` ### 3. Install Certbot ```bash sudo apt install -y certbot python3-certbot-nginx ``` --- ## πŸ“¦ Application Deployment ### 1. Clone Repository ```bash cd /opt sudo git clone https://github.com/dnoulet/go-first.git sudo chown -R deploy:deploy go-first cd go-first ``` ### 2. Configure Environment ```bash # Copy production template cp .env.production.example .env.production # Edit with your values (use strong passwords!) vim .env.production # Required changes: # - DATABASE_PASSWORD: Strong random password # - JWT_SECRET: 32+ char random string # - EMAIL_*: Your SMTP credentials ``` ### 3. Generate SSL Certificates ```bash # Stop any service on port 80 sudo systemctl stop nginx 2>/dev/null || true # Get certificates sudo certbot certonly --standalone \ -d www.urpi.be \ -d urpi.be \ --email daniel.noulet@urpi.be \ --agree-tos --non-interactive # Certificates will be at: # /etc/letsencrypt/live/www.urpi.be/fullchain.pem # /etc/letsencrypt/live/www.urpi.be/privkey.pem ``` ### 4. Setup NGINX SSL Directory ```bash sudo mkdir -p /opt/go-first/deploy/ssl sudo cp /etc/letsencrypt/live/www.urpi.be/fullchain.pem /opt/go-first/deploy/ssl/ sudo cp /etc/letsencrypt/live/www.urpi.be/privkey.pem /opt/go-first/deploy/ssl/ sudo chown -R deploy:deploy /opt/go-first/deploy/ssl ``` ### 5. Deploy with Docker Compose ```bash cd /opt/go-first # Build and start docker compose --env-file .env.production up -d --build # Verify docker compose --env-file .env.production ps docker compose --env-file .env.production logs -f app ``` ### 6. Verify Deployment ```bash # Health check curl -f https://www.urpi.be/api/v1/health # Check frontend curl -f https://www.urpi.be/ | grep -c "URPI" ``` --- ## πŸ” SSL Certificate Renewal ### Automatic Renewal (systemd timer) ```bash # Check certbot timer sudo systemctl status certbot.timer # Test renewal sudo certbot renew --dry-run ``` ### Manual Renewal Hook ```bash # Create renewal hook sudo tee /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh > /dev/null <<'EOF' #!/bin/bash cp /etc/letsencrypt/live/www.urpi.be/fullchain.pem /opt/go-first/deploy/ssl/ cp /etc/letsencrypt/live/www.urpi.be/privkey.pem /opt/go-first/deploy/ssl/ docker compose -f /opt/go-first/docker-compose.yml --env-file /opt/go-first/.env.production exec nginx nginx -s reload EOF sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh ``` --- ## πŸ—„οΈ Database Management ### Backup ```bash # Create backup script cat > /opt/go-first/backup.sh <<'EOF' #!/bin/bash set -euo pipefail BACKUP_DIR="/opt/backups/go-first" DATE=$(date +%Y%m%d_%H%M%S) mkdir -p "$BACKUP_DIR" docker compose -f /opt/go-first/docker-compose.yml --env-file /opt/go-first/.env.production \ exec -T postgres pg_dump -U postgres go_first | gzip > "$BACKUP_DIR/go_first_$DATE.sql.gz" # Keep last 30 days find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete echo "Backup saved to $BACKUP_DIR/go_first_$DATE.sql.gz" EOF chmod +x /opt/go-first/backup.sh # Add to crontab (daily at 2 AM) (crontab -l 2>/dev/null; echo "0 2 * * * /opt/go-first/backup.sh") | crontab - ``` ### Restore ```bash # Stop app docker compose -f /opt/go-first/docker-compose.yml --env-file /opt/go-first/.env.production stop app # Restore gunzip -c /opt/backups/go-first/go_first_20240115_020000.sql.gz | \ docker compose -f /opt/go-first/docker-compose.yml --env-file /opt/go-first/.env.production exec -T postgres psql -U postgres go_first # Start app docker compose -f /opt/go-first/docker-compose.yml --env-file /opt/go-first/.env.production start app ``` --- ## πŸ“Š Monitoring & Logging ### Log Aggregation (Optional: Loki + Promtail) ```yaml # Add to docker-compose.yml services: promtail: image: grafana/promtail:2.9 volumes: - /var/log:/var/log - /opt/go-first/deploy/promtail.yml:/etc/promtail/config.yml depends_on: - loki loki: image: grafana/loki:2.9 volumes: - loki_data:/loki ``` ### Health Checks ```bash # Application health curl https://www.urpi.be/api/v1/health # Database docker compose exec postgres pg_isready -U postgres # Redis docker compose exec redis redis-cli ping # NGINX docker compose exec nginx nginx -t ``` ### Metrics (Optional: Prometheus + Grafana) Add to `docker-compose.yml`: ```yaml prometheus: image: prom/prometheus:v2.47 volumes: - ./deploy/prometheus.yml:/etc/prometheus/prometheus.yml - prometheus_data:/prometheus ports: - "9090:9090" grafana: image: grafana/grafana:10.2 ports: - "3000:3000" volumes: - grafana_data:/var/lib/grafana ``` --- ## πŸ”„ Updates & Rollbacks ### Update Application ```bash cd /opt/go-first # Pull latest code git pull origin main # Rebuild and deploy docker compose --env-file .env.production up -d --build --remove-orphans # Verify curl -f https://www.urpi.be/api/v1/health ``` ### Rollback ```bash # List images docker images ghcr.io/dnoulet/go-first # Rollback to previous tag docker tag ghcr.io/dnoulet/go-first:previous-tag ghcr.io/dnoulet/go-first:latest docker compose --env-file .env.production up -d --no-deps app ``` ### Zero-Downtime Deploy (with multiple replicas) ```yaml # In docker-compose.yml, add: deploy: replicas: 2 update_config: parallelism: 1 delay: 10s order: start-first restart_policy: condition: on-failure ``` --- ## πŸ›‘οΈ Security Checklist - [ ] Strong DATABASE_PASSWORD (32+ chars) - [ ] Strong JWT_SECRET (32+ chars, random) - [ ] SMTP credentials secured - [ ] Firewall: only 22, 80, 443 open - [ ] SSH key-only authentication - [ ] Fail2ban configured for SSH - [ ] Regular security updates (`apt update && apt upgrade`) - [ ] Docker images scanned for vulnerabilities (`docker scout cves`) - [ ] NGINX security headers enabled - [ ] Rate limiting configured - [ ] CSP headers configured - [ ] HSTS enabled - [ ] Database not exposed publicly - [ ] Redis not exposed publicly - [ ] Backup encryption at rest - [ ] Audit logging enabled --- ## 🚨 Troubleshooting ### Application Won't Start ```bash # Check logs docker compose --env-file .env.production logs app # Common issues: # - Port 8080 already in use # - Database connection failed # - Config file missing # - Permission denied on volumes ``` ### 502 Bad Gateway ```bash # Check if app is healthy docker compose --env-file .env.production ps app # Check NGINX config docker compose --env-file .env.production exec nginx nginx -t # Check upstream docker compose --env-file .env.production exec nginx curl -f http://app:8080/api/v1/health ``` ### SSL Certificate Issues ```bash # Check certificate validity openssl x509 -in /etc/letsencrypt/live/www.urpi.be/fullchain.pem -text -noout # Check NGINX SSL config docker compose --env-file .env.production exec nginx nginx -T | grep ssl ``` ### Database Connection Issues ```bash # Test connection docker compose --env-file .env.production exec postgres psql -U postgres -d go_first -c "SELECT 1;" # Check credentials in .env.production match docker-compose.yml ``` --- ## πŸ“ž Support For deployment issues: - Check logs: `docker compose logs -f` - Review this guide - Contact: daniel.noulet@urpi.be --- ## πŸ“ Maintenance Windows Recommended: **Sunday 02:00-04:00 UTC** - System updates - Docker image updates - Database maintenance - Certificate renewal verification