This commit is contained in:
Matthias Hochmeister
2026-02-23 17:08:58 +01:00
commit f09748f4a1
97 changed files with 17729 additions and 0 deletions

704
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,704 @@
# 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/)