# 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 ``` --- ## 🚀 Quick Start (One Command) ```bash cd /srv/digiserver-v2 bash deploy.sh ``` This will: 1. ✅ Start Docker containers 2. ✅ Initialize database 3. ✅ Run migrations 4. ✅ Configure HTTPS 5. ✅ Display access information --- ## 📦 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** ```bash 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: 1. Create required directories 2. Check if database exists 3. If NOT exists: - Initialize SQLite database (dashboard.db) - Create admin user from environment variables 4. Start Gunicorn server (4 workers, 120s timeout) ### **Step 3: Run Migrations** ```bash docker-compose exec -T digiserver-app python /app/migrations/[migration_name].py ``` Applied migrations: - `add_https_config_table.py` - HTTPS settings - `add_player_user_table.py` - Player user management - `add_email_to_https_config.py` - Email configuration - `migrate_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 IP - `X-Forwarded-Proto` → Protocol (http/https) - `X-Forwarded-Host` → Original hostname - `X-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://` (if DNS configured) --- ## ⚙️ Environment Variables (Optional) Create `.env` file in project root: ```bash # 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: ```bash docker-compose up -d ``` --- ## 🛠️ Common Commands ### **Start/Stop Containers** ```bash # 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** ```bash # 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** ```bash # 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** ```bash # 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** ```bash # 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 bash generate_nginx_certs.sh 192.168.0.121 365 docker-compose restart nginx ``` Parameters: - `192.168.0.121` - Domain/IP for certificate - `365` - Certificate validity in days ### **Set Up Let's Encrypt (Production)** 1. Update `DOMAIN` and `EMAIL` in environment 2. Modify `nginx.conf` to enable certbot challenges 3. Run certbot: ```bash 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?** ```bash # Check docker-compose logs docker-compose logs # Check system resources docker stats # Restart Docker daemon sudo systemctl restart docker ``` ### **Application not responding?** ```bash # 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?** ```bash # 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?** ```bash # 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?** ```bash # 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 ``` --- ## 📊 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: ```bash docker-compose ps # Look for "Up (healthy)" status ``` --- ## 🔄 Database Backup & Restore ### **Backup** ```bash # 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** ```bash # 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) ```bash # 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) ```nginx # Default: auto (CPU count) worker_processes auto; # Or specify manually: worker_processes 4; ``` ### **Upload Timeout** (nginx.conf) ```nginx # Default: 300s proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; ``` --- ## 🔐 Security Checklist - [ ] Change admin password immediately - [ ] Set strong `SECRET_KEY` environment 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-v2` directory - [ ] 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 1. **Access Web Interface** - Login with admin credentials - Change password immediately 2. **Configure Application** - Set up players - Upload content - Configure groups & permissions 3. **Production Hardening** - Enable Let's Encrypt HTTPS - Configure firewall rules - Set up database backups - Monitor logs 4. **Optional Enhancements** - Set up custom domain - Configure email notifications - Install optional dependencies (LibreOffice, etc.) --- **Last Updated**: January 15, 2026