- Implement Docker image-based deployment (Option 1) * Code immutable in image, no volume override * Eliminated init-data.sh manual step * Simplified deployment process - Unified persistence in data/ folder * Moved nginx.conf and nginx-custom-domains.conf to data/ * All runtime configs and data in single location * Clear separation: repo (source) vs data/ (runtime) - Archive legacy features * Groups blueprint and templates removed * Legacy playlist routes redirected to content area * Organized in old_code_documentation/ - Added network migration support * New migrate_network.sh script for IP changes * Regenerates SSL certs for new IP * Updates database configuration * Tested workflow: clone → deploy → migrate - Enhanced deploy.sh * Creates data directories * Copies nginx configs from repo to data/ * Validates file existence before deployment * Prevents incomplete deployments - Updated documentation * QUICK_DEPLOYMENT.md shows 4-step workflow * Complete deployment workflow documented * Migration procedures included - Production ready deployment workflow: 1. Clone & setup (.env configuration) 2. Deploy (./deploy.sh) 3. Migrate network (./migrate_network.sh if needed) 4. Normal operations (docker compose restart)
12 KiB
DigiServer v2 - Quick Deployment Guide
📋 Overview
DigiServer is deployed using Docker Compose with the following architecture:
Internet (User)
↓
Nginx Reverse Proxy (Port 80/443)
↓
Internal Docker Network
↓
Flask App (Gunicorn on Port 5000)
↓
SQLite Database
🚀 Complete Deployment Workflow
1️⃣ Clone & Setup
# Copy the app folder from repository
git clone <repository>
cd digiserver-v2
# Copy environment file and modify as needed
cp .env.example .env
# Edit .env with your configuration:
nano .env
Configure in .env:
SECRET_KEY=your-secret-key-change-this
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your-secure-password
DOMAIN=your-domain.com
EMAIL=admin@your-domain.com
IP_ADDRESS=192.168.0.111
2️⃣ Deploy via Script
# Run the deployment script
./deploy.sh
This automatically:
- ✅ Creates
data/directories (instance, uploads, nginx-ssl, etc.) - ✅ Copies nginx configs from repo root to
data/ - ✅ Starts Docker containers
- ✅ Initializes database
- ✅ Runs all migrations
- ✅ Configures HTTPS with SSL certificates
- ✅ Displays access information
Output shows:
- Access URLs (HTTP/HTTPS)
- Default credentials
- Next steps for configuration
3️⃣ Network Migration (When Network Changes)
When moving the server to a different network with a new IP:
# Migrate to the new network IP
./migrate_network.sh 10.55.150.160
# Optional: with custom hostname
./migrate_network.sh 10.55.150.160 digiserver-secured
This automatically:
- ✅ Regenerates SSL certificates for new IP
- ✅ Updates database HTTPS configuration
- ✅ Restarts nginx and app containers
- ✅ Verifies HTTPS connectivity
4️⃣ Normal Operations
Restart containers:
docker compose restart
Stop containers:
docker compose down
View logs:
docker compose logs -f
View container status:
docker compose ps
📦 Container Architecture
Container 1: digiserver-app (Flask)
- Image: Built from Dockerfile (Python 3.13)
- Port: 5000 (internal only)
- Volumes:
./data:/app- Persistent application data./data/instance:/app/instance- Database & configuration./data/uploads:/app/app/static/uploads- User uploads
- Startup: Automatically initializes database on first run
- Health Check: Every 30 seconds
Container 2: nginx (Reverse Proxy)
- Image: nginx:alpine
- Ports: 80 & 443 (exposed to internet)
- Volumes:
nginx.conf- Main configuration./data/nginx-ssl/- SSL certificates./data/nginx-logs/- Access/error logs./data/certbot/- Let's Encrypt challenges
- Startup: Waits for Flask app to start
- Health Check: Every 30 seconds
🔧 Deployment Steps Explained
Step 1: Start Containers
docker-compose up -d
- Builds Flask app image (if needed)
- Starts both containers
- Waits for containers to be healthy
Step 2: Database Initialization (docker-entrypoint.sh)
When Flask container starts:
- Create required directories
- Check if database exists
- If NOT exists:
- Initialize SQLite database (dashboard.db)
- Create admin user from environment variables
- Start Gunicorn server (4 workers, 120s timeout)
Step 3: Run Migrations
docker-compose exec -T digiserver-app python /app/migrations/[migration_name].py
Applied migrations:
add_https_config_table.py- HTTPS settingsadd_player_user_table.py- Player user managementadd_email_to_https_config.py- Email configurationmigrate_player_user_global.py- Global settings
Step 4: Configure HTTPS
- SSL certificates stored in
./data/nginx-ssl/ - Pre-generated self-signed certs for development
- Ready for Let's Encrypt integration
Step 5: Reverse Proxy Routing (nginx.conf)
HTTP (80):
• Redirect all traffic to HTTPS
• Allow ACME challenges for Let's Encrypt
HTTPS (443):
• TLS 1.2+, HTTP/2 enabled
• Proxy all requests to Flask app
• Security headers added
• Gzip compression enabled
• Max upload size: 2GB
• Proxy timeout: 300s
Step 6: ProxyFix Middleware (app/app.py)
Extracts real client information from Nginx headers:
X-Forwarded-For→ Real client IPX-Forwarded-Proto→ Protocol (http/https)X-Forwarded-Host→ Original hostnameX-Forwarded-Port→ Original port
📂 Directory Structure & Persistence
/srv/digiserver-v2/
├── app/ (Flask application code)
├── data/ (PERSISTENT - mounted as Docker volume)
│ ├── app/ (Copy of app/ for container)
│ ├── instance/ (dashboard.db - SQLite database)
│ ├── uploads/ (User uploaded files)
│ ├── nginx-ssl/ (SSL certificates)
│ ├── nginx-logs/ (Nginx logs)
│ └── certbot/ (Let's Encrypt challenges)
├── migrations/ (Database schema updates)
├── docker-compose.yml (Container orchestration)
├── Dockerfile (Flask app image definition)
├── nginx.conf (Reverse proxy configuration)
└── docker-entrypoint.sh (Container startup script)
🔐 Default Credentials
Username: admin
Password: admin123
⚠️ CHANGE IMMEDIATELY IN PRODUCTION!
🌐 Access Points
After deployment, access the app at:
https://localhost(if deployed locally)https://192.168.0.121(if deployed on server)https://<DOMAIN>(if DNS configured)
⚙️ Environment Variables (Optional)
Create .env file in project root:
# Network Configuration
HOSTNAME=digiserver
DOMAIN=digiserver.example.com
IP_ADDRESS=192.168.0.121
# SSL/HTTPS
EMAIL=admin@example.com
# Flask Configuration
SECRET_KEY=your-secret-key-here
FLASK_ENV=production
# Admin User
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin123
Then start with:
docker-compose up -d
🛠️ Common Commands
Start/Stop Containers
# Start containers
docker-compose up -d
# Stop containers
docker-compose down
# Restart containers
docker-compose restart
# Restart specific container
docker-compose restart digiserver-app
docker-compose restart nginx
View Logs
# All containers
docker-compose logs
# Follow logs (real-time)
docker-compose logs -f
# Specific container
docker-compose logs -f digiserver-app
docker-compose logs -f nginx
# Show last 50 lines
docker-compose logs --tail=50 digiserver-app
Container Status
# Show running containers
docker-compose ps
# Show container details
docker-compose ps -a
# Check container health
docker ps --format="table {{.Names}}\t{{.Status}}"
Database Operations
# Access database shell
docker-compose exec digiserver-app sqlite3 /app/instance/dashboard.db
# Backup database
docker-compose exec digiserver-app cp /app/instance/dashboard.db /app/instance/dashboard.db.backup
# Restore database
docker-compose exec digiserver-app cp /app/instance/dashboard.db.backup /app/instance/dashboard.db
Nginx Operations
# Validate Nginx configuration
docker exec digiserver-nginx nginx -t
# Reload Nginx (without restart)
docker exec digiserver-nginx nginx -s reload
# View Nginx logs
docker-compose logs -f nginx
🔒 SSL Certificate Management
Generate New Self-Signed Certificate
bash generate_nginx_certs.sh 192.168.0.121 365
docker-compose restart nginx
Parameters:
192.168.0.121- Domain/IP for certificate365- Certificate validity in days
Set Up Let's Encrypt (Production)
- Update
DOMAINandEMAILin environment - Modify
nginx.confto enable certbot challenges - Run certbot:
docker run --rm -v $(pwd)/data/certbot:/etc/letsencrypt \ -v $(pwd)/data/nginx-logs:/var/log/letsencrypt \ certbot/certbot certonly --webroot \ -w /var/www/certbot \ -d yourdomain.com \ -m your-email@example.com \ --agree-tos
🐛 Troubleshooting
Containers not starting?
# Check docker-compose logs
docker-compose logs
# Check system resources
docker stats
# Restart Docker daemon
sudo systemctl restart docker
Application not responding?
# Check app container health
docker-compose ps
# View app logs
docker-compose logs -f digiserver-app
# Test Flask directly
docker-compose exec digiserver-app curl http://localhost:5000/
HTTPS not working?
# Verify Nginx config
docker exec digiserver-nginx nginx -t
# Check SSL certificates exist
ls -la ./data/nginx-ssl/
# View Nginx error logs
docker-compose logs nginx
Database issues?
# Check database file exists
ls -la ./data/instance/dashboard.db
# Verify database permissions
docker-compose exec digiserver-app ls -la /app/instance/
# Check database tables
docker-compose exec digiserver-app sqlite3 /app/instance/dashboard.db ".tables"
Port already in use?
# Find process using port 80
sudo lsof -i :80
# Find process using port 443
sudo lsof -i :443
# Kill process (if needed)
sudo kill -9 <PID>
📊 Health Checks
Both containers have health checks:
Flask App: Pings http://localhost:5000/ every 30 seconds
Nginx: Pings http://localhost:80/ every 30 seconds
Check health status:
docker-compose ps
# Look for "Up (healthy)" status
🔄 Database Backup & Restore
Backup
# Create backup
docker-compose exec digiserver-app cp /app/instance/dashboard.db /app/instance/dashboard.backup.db
# Download to local machine
cp ./data/instance/dashboard.backup.db ./backup/
Restore
# Stop containers
docker-compose stop
# Restore database
cp ./backup/dashboard.backup.db ./data/instance/dashboard.db
# Start containers
docker-compose up -d
📈 Performance Tuning
Gunicorn Workers (docker-entrypoint.sh)
# Default: 4 workers
# Formula: (2 × CPU_count) + 1
# For 4-core CPU: 9 workers
# Modify docker-entrypoint.sh:
gunicorn --workers 9 ...
Nginx Worker Processes (nginx.conf)
# Default: auto (CPU count)
worker_processes auto;
# Or specify manually:
worker_processes 4;
Upload Timeout (nginx.conf)
# Default: 300s
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
🔐 Security Checklist
- Change admin password immediately
- Set strong
SECRET_KEYenvironment variable - Enable firewall rules (allow only ports 80, 443)
- Set up HTTPS with Let's Encrypt
- Configure regular database backups
- Review Nginx security headers
- Update Flask dependencies regularly
- Monitor container logs for errors
- Restrict admin panel access (IP whitelist optional)
- Enable Flask debug mode only in development
📞 Support & Documentation
- Nginx Setup: See
NGINX_SETUP_QUICK.md - ProxyFix Configuration: See
PROXY_FIX_SETUP.md - Deployment Commands: See
DEPLOYMENT_COMMANDS.md - Issue Troubleshooting: Check
old_code_documentation/
✅ Deployment Checklist
- Docker & Docker Compose installed
- Running from
/srv/digiserver-v2directory - Environment variables configured (optional)
- Port 80/443 available
- Sufficient disk space (min 5GB)
- Sufficient RAM (min 2GB free)
- Network connectivity verified
- SSL certificates generated or obtained
- Admin credentials changed (production)
🚀 Next Steps After Deployment
-
Access Web Interface
- Login with admin credentials
- Change password immediately
-
Configure Application
- Set up players
- Upload content
- Configure groups & permissions
-
Production Hardening
- Enable Let's Encrypt HTTPS
- Configure firewall rules
- Set up database backups
- Monitor logs
-
Optional Enhancements
- Set up custom domain
- Configure email notifications
- Install optional dependencies (LibreOffice, etc.)
Last Updated: January 15, 2026