go-first/docs/DEPLOYMENT.md

425 lines
9.2 KiB
Markdown
Raw Normal View History

2026-10-07 15:21:47 +02:00
# 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 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
```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: contact@urpi.be
---
## 📝 Maintenance Windows
Recommended: **Sunday 02:00-04:00 UTC**
- System updates
- Docker image updates
- Database maintenance
- Certificate renewal verification