initial commit
This commit is contained in:
commit
e7987e88a7
70 changed files with 13661 additions and 0 deletions
425
docs/DEPLOYMENT.md
Normal file
425
docs/DEPLOYMENT.md
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
# 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue