9.2 KiB
9.2 KiB
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
# 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
# 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
sudo apt install -y certbot python3-certbot-nginx
📦 Application Deployment
1. Clone Repository
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
# 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
# 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 contact@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
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
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
# 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)
# Check certbot timer
sudo systemctl status certbot.timer
# Test renewal
sudo certbot renew --dry-run
Manual Renewal Hook
# 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
# 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
# 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)
# 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
# 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:
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
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
# 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)
# 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
# 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
# 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
# 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
# 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: contact@urpi.be
📝 Maintenance Windows
Recommended: Sunday 02:00-04:00 UTC
- System updates
- Docker image updates
- Database maintenance
- Certificate renewal verification