# Production Deployment Guide This guide walks you through deploying the Feuerwehr Dashboard in a production environment. ## Table of Contents - [Server Requirements](#server-requirements) - [Pre-Deployment Checklist](#pre-deployment-checklist) - [Deployment Steps](#deployment-steps) - [Authentik Configuration](#authentik-configuration) - [SSL/HTTPS Setup](#ssl-https-setup) - [Database Management](#database-management) - [Monitoring Setup](#monitoring-setup) - [Update Procedures](#update-procedures) - [Rollback Procedures](#rollback-procedures) - [Performance Tuning](#performance-tuning) - [Security Hardening](#security-hardening) ## Server Requirements ### Minimum Requirements - **CPU**: 2 cores - **RAM**: 2 GB (4 GB recommended) - **Storage**: 20 GB SSD - **OS**: Ubuntu 20.04+ / Debian 11+ / CentOS 8+ / RHEL 8+ - **Docker**: 20.10+ - **Docker Compose**: 2.0+ ### Network Requirements Open the following ports: - **80** - HTTP (will redirect to HTTPS) - **443** - HTTPS (if using SSL) - **3000** - Backend API (can be internal only) - **5432** - PostgreSQL (should be internal only) ### Recommended Production Specs - **CPU**: 4 cores - **RAM**: 8 GB - **Storage**: 50 GB SSD with RAID for database - **Network**: 100 Mbps minimum ## Pre-Deployment Checklist Before deploying to production: - [ ] Server meets minimum requirements - [ ] Docker and Docker Compose installed - [ ] Domain name configured (DNS A record pointing to server) - [ ] Authentik instance available and accessible - [ ] SSL certificates obtained (Let's Encrypt or commercial) - [ ] Firewall configured - [ ] Backup strategy planned - [ ] Monitoring solution chosen - [ ] All secrets and credentials prepared ## Deployment Steps ### Step 1: Server Preparation Update system packages: ```bash # Ubuntu/Debian sudo apt update && sudo apt upgrade -y # CentOS/RHEL sudo yum update -y ``` Install Docker: ```bash # Ubuntu/Debian curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER # CentOS/RHEL sudo yum install -y docker sudo systemctl start docker sudo systemctl enable docker ``` Install Docker Compose: ```bash sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose docker-compose --version ``` Configure firewall: ```bash # Ubuntu/Debian (UFW) sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable # CentOS/RHEL (firewalld) sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --reload ``` ### Step 2: Clone Repository ```bash cd /opt sudo git clone feuerwehr_dashboard cd feuerwehr_dashboard sudo chown -R $USER:$USER . ``` ### Step 3: Configure Environment Generate secure secrets: ```bash # Generate JWT secret (save this!) openssl rand -base64 32 # Generate strong database password (save this!) openssl rand -base64 24 ``` Create `.env` file: ```bash cp .env.example .env nano .env ``` Configure the following critical variables: ```bash # Database - Use strong passwords! POSTGRES_DB=feuerwehr_prod POSTGRES_USER=prod_user POSTGRES_PASSWORD= POSTGRES_PORT=5432 # Backend BACKEND_PORT=3000 NODE_ENV=production # JWT - Use generated secret! JWT_SECRET= # CORS - Set to your domain! CORS_ORIGIN=https://dashboard.yourdomain.com # Frontend FRONTEND_PORT=80 # API URL - Set to your backend URL VITE_API_URL=https://api.yourdomain.com # Authentik OAuth (from Authentik setup) AUTHENTIK_CLIENT_ID= AUTHENTIK_CLIENT_SECRET= AUTHENTIK_ISSUER=https://auth.yourdomain.com/application/o/feuerwehr/ AUTHENTIK_REDIRECT_URI=https://dashboard.yourdomain.com/auth/callback ``` Secure the .env file: ```bash chmod 600 .env ``` ### Step 4: Initial Deployment Deploy the application: ```bash make prod # or ./deploy.sh production ``` Verify all services are running: ```bash docker-compose ps ``` Expected output: ``` NAME STATUS PORTS feuerwehr_backend_prod Up (healthy) 0.0.0.0:3000->3000/tcp feuerwehr_db_prod Up (healthy) 0.0.0.0:5432->5432/tcp feuerwehr_frontend_prod Up (healthy) 0.0.0.0:80->80/tcp ``` Check logs for errors: ```bash make logs-prod ``` ### Step 5: Database Initialization The database will be automatically initialized on first start using the migration scripts in `backend/src/database/migrations/`. Verify database tables: ```bash docker exec -it feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod -c "\dt" ``` ### Step 6: Test the Deployment Test health endpoints: ```bash # Backend health check curl http://localhost:3000/health # Frontend availability curl http://localhost:80 ``` Test authentication flow: 1. Open browser to `http://localhost` (or your domain) 2. Click login 3. Authenticate with Authentik 4. Verify redirect back to dashboard 5. Verify user profile loads ## Authentik Configuration See [AUTHENTIK_SETUP.md](AUTHENTIK_SETUP.md) for complete Authentik configuration. Key points for production: 1. **Use HTTPS URLs** for all redirect URIs 2. **Configure proper scopes**: `openid`, `profile`, `email` 3. **Set token expiration** appropriately (e.g., 3600s for access, 86400s for refresh) 4. **Enable required claims** in the provider 5. **Test the flow** thoroughly before going live ## SSL/HTTPS Setup ### Option 1: Using Caddy (Recommended) Create `Caddyfile`: ```caddy dashboard.yourdomain.com { reverse_proxy localhost:80 encode gzip header { Strict-Transport-Security "max-age=31536000;" X-Content-Type-Options "nosniff" X-Frame-Options "DENY" Referrer-Policy "strict-origin-when-cross-origin" } } api.yourdomain.com { reverse_proxy localhost:3000 encode gzip } ``` Run Caddy: ```bash docker run -d \ --name caddy \ --network host \ -v $PWD/Caddyfile:/etc/caddy/Caddyfile \ -v caddy_data:/data \ -v caddy_config:/config \ --restart unless-stopped \ caddy:latest ``` Caddy will automatically obtain and renew SSL certificates from Let's Encrypt. ### Option 2: Using Nginx with Certbot Install Nginx and Certbot: ```bash sudo apt install nginx certbot python3-certbot-nginx -y ``` Create Nginx configuration (`/etc/nginx/sites-available/feuerwehr`): ```nginx server { listen 80; server_name dashboard.yourdomain.com; location / { proxy_pass http://localhost:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Enable and obtain SSL: ```bash sudo ln -s /etc/nginx/sites-available/feuerwehr /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx sudo certbot --nginx -d dashboard.yourdomain.com -d api.yourdomain.com ``` ### Option 3: Using Docker with Traefik See community guides for Traefik integration. ## Database Management ### Backup Procedures Create automated backup script (`/opt/backup-feuerwehr-db.sh`): ```bash #!/bin/bash BACKUP_DIR="/opt/backups/feuerwehr" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/feuerwehr_backup_$DATE.sql.gz" mkdir -p $BACKUP_DIR docker exec feuerwehr_db_prod pg_dump -U prod_user feuerwehr_prod | gzip > $BACKUP_FILE # Keep only last 30 days of backups find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete echo "Backup completed: $BACKUP_FILE" ``` Make executable and schedule: ```bash chmod +x /opt/backup-feuerwehr-db.sh # Add to crontab (daily at 2 AM) crontab -e 0 2 * * * /opt/backup-feuerwehr-db.sh >> /var/log/feuerwehr-backup.log 2>&1 ``` ### Restore Procedures Restore from backup: ```bash # Stop backend service docker-compose stop backend # Restore database gunzip -c /opt/backups/feuerwehr/feuerwehr_backup_20260223_020000.sql.gz | \ docker exec -i feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod # Restart backend docker-compose start backend ``` ### Database Maintenance Regular vacuum and analyze: ```bash docker exec feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod -c "VACUUM ANALYZE;" ``` ## Monitoring Setup ### Basic Health Monitoring Create monitoring script (`/opt/monitor-feuerwehr.sh`): ```bash #!/bin/bash # Check backend health BACKEND_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health) if [ "$BACKEND_STATUS" != "200" ]; then echo "Backend health check failed: $BACKEND_STATUS" # Send alert (email, Slack, etc.) fi # Check database DB_STATUS=$(docker exec feuerwehr_db_prod pg_isready -U prod_user) if [ $? -ne 0 ]; then echo "Database health check failed" # Send alert fi # Check container status CONTAINERS=$(docker-compose ps --services --filter "status=running" | wc -l) if [ "$CONTAINERS" -lt 3 ]; then echo "Not all containers are running" # Send alert fi ``` Schedule monitoring: ```bash chmod +x /opt/monitor-feuerwehr.sh crontab -e */5 * * * * /opt/monitor-feuerwehr.sh >> /var/log/feuerwehr-monitor.log 2>&1 ``` ### Recommended Monitoring Tools - **Prometheus + Grafana** - Metrics and dashboards - **Loki** - Log aggregation - **Uptime Kuma** - Simple uptime monitoring - **Portainer** - Docker container management ## Update Procedures ### Standard Update Process 1. **Backup everything**: ```bash /opt/backup-feuerwehr-db.sh docker-compose down tar -czf /opt/backups/feuerwehr_config_$(date +%Y%m%d).tar.gz .env docker-compose.yml ``` 2. **Pull latest changes**: ```bash git pull origin main ``` 3. **Review changes**: ```bash git log --oneline -10 git diff HEAD~1 .env.example ``` 4. **Update environment** if needed: ```bash # Compare .env.example with your .env diff .env.example .env # Add any new required variables ``` 5. **Rebuild and deploy**: ```bash make rebuild # or ./deploy.sh rebuild ``` 6. **Verify update**: ```bash docker-compose ps make logs-prod # Test critical functionality ``` ### Zero-Downtime Updates For zero-downtime updates, use blue-green deployment: 1. Set up second environment 2. Deploy new version to green 3. Test green environment 4. Switch traffic (using load balancer) 5. Shut down blue environment ## Rollback Procedures ### Quick Rollback If issues arise after update: 1. **Stop current version**: ```bash docker-compose down ``` 2. **Restore previous version**: ```bash git log --oneline -5 # Find previous commit git checkout ``` 3. **Restore database** if schema changed: ```bash gunzip -c /opt/backups/feuerwehr/feuerwehr_backup_.sql.gz | \ docker exec -i feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod ``` 4. **Redeploy**: ```bash make prod ``` ### Tagged Releases Use Git tags for stable releases: ```bash # Tag a release git tag -a v1.0.0 -m "Production release 1.0.0" git push origin v1.0.0 # Deploy specific release git checkout v1.0.0 make prod ``` ## Performance Tuning ### Database Optimization Edit PostgreSQL configuration in `docker-compose.yml`: ```yaml postgres: command: - "postgres" - "-c" - "max_connections=100" - "-c" - "shared_buffers=256MB" - "-c" - "effective_cache_size=1GB" - "-c" - "work_mem=4MB" ``` ### Backend Optimization Add environment variables to backend: ```bash # In .env NODE_OPTIONS=--max-old-space-size=2048 ``` ### Frontend Optimization Already optimized: - Vite build optimization - Gzip compression in Nginx - Static asset caching ### Docker Resource Limits Add resource limits to `docker-compose.yml`: ```yaml backend: deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '0.5' memory: 512M ``` ## Security Hardening ### Docker Security Run containers as non-root: ```yaml backend: user: "node" postgres: user: "postgres" ``` ### Network Security Isolate database from external access: ```yaml postgres: # Remove ports mapping for production # ports: # - "5432:5432" # Database is only accessible via Docker network ``` ### Environment Security Protect sensitive files: ```bash chmod 600 .env chmod 600 docker-compose.yml ``` ### Regular Security Updates Set up automatic security updates: ```bash # Ubuntu/Debian sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades ``` ### Security Monitoring - Enable Docker security scanning - Monitor logs for suspicious activity - Set up fail2ban for SSH protection - Regular security audits ## Post-Deployment After successful deployment: 1. **Document your setup** - Note any custom configurations 2. **Train your team** - Ensure team knows how to use the system 3. **Set up alerts** - Configure notifications for issues 4. **Schedule maintenance** - Plan for regular updates and backups 5. **Review security** - Regular security audits 6. **Monitor performance** - Track metrics and optimize as needed ## Troubleshooting ### Services Won't Start Check logs: ```bash docker-compose logs ``` Check resources: ```bash docker stats df -h free -h ``` ### SSL Certificate Issues Renew certificates: ```bash sudo certbot renew ``` ### Performance Issues Check resource usage: ```bash docker stats htop iotop ``` Optimize database: ```bash docker exec feuerwehr_db_prod psql -U prod_user -d feuerwehr_prod -c "VACUUM FULL ANALYZE;" ``` ## Support For production support issues: 1. Check logs first 2. Review this deployment guide 3. Consult [TROUBLESHOOTING](README.md#troubleshooting) section 4. Create detailed issue report 5. Contact support team ## Additional Resources - [Docker Documentation](https://docs.docker.com/) - [PostgreSQL Performance Tuning](https://wiki.postgresql.org/wiki/Performance_Optimization) - [Node.js Production Best Practices](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/) - [Authentik Documentation](https://goauthentik.io/docs/)