705 lines
14 KiB
Markdown
705 lines
14 KiB
Markdown
# 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 <your-repository-url> 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=<generated-secure-password>
|
|
POSTGRES_PORT=5432
|
|
|
|
# Backend
|
|
BACKEND_PORT=3000
|
|
NODE_ENV=production
|
|
|
|
# JWT - Use generated secret!
|
|
JWT_SECRET=<generated-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=<your-client-id>
|
|
AUTHENTIK_CLIENT_SECRET=<your-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 <previous-commit-hash>
|
|
```
|
|
|
|
3. **Restore database** if schema changed:
|
|
```bash
|
|
gunzip -c /opt/backups/feuerwehr/feuerwehr_backup_<timestamp>.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/)
|