# DigiServer v2 - Quick Deployment Guide ## 📋 Overview DigiServer is deployed using Docker Compose with the following architecture: ``` Internet (User) — Port 8080 (HTTP) / 8443 (HTTPS) ↓ Caddy Reverse Proxy (auto HTTPS, gzip, security headers) ↓ Internal Docker Network (digiserver-network) ↓ Flask App (Gunicorn on Port 5000) ↓ SQLite Database ``` Caddy is used instead of Nginx because it: - **Auto-provisions Let's Encrypt certificates** — no manual certbot - **Simpler config** — a `Caddyfile` replaces the verbose `nginx.conf` - **Built-in HTTP/2, gzip, security headers** - **Admin API** (port 2019) — Flask reloads Caddy config dynamically --- ## 🚀 Quick Start ### **1️⃣ Clone & Setup** ```bash git clone cd digiserver-v2 ``` ### **2️⃣ Start Containers** ```bash docker compose up -d ``` This automatically: 1. ✅ Builds the Flask app image from `Dockerfile` 2. ✅ Creates persistent data directories (`data/instance`, `data/uploads`, etc.) 3. ✅ Starts Caddy reverse proxy on ports **8080** (HTTP) and **8443** (HTTPS) 4. ✅ Initializes the database on first run (auto-creates admin user) 5. ✅ Runs all required migrations **Access the app at:** `http://localhost:8080` ### **3️⃣ First-Time Login** ``` URL: http://localhost:8080 Username: admin Password: admin123 ``` ⚠️ **CHANGE PASSWORD IMMEDIATELY IN PRODUCTION!** --- ## 📦 Container Architecture ### **Container 1: digiserver-app (Flask)** | Property | Value | |----------|-------| | **Image** | Built from `Dockerfile` (Python 3.13-slim) | | **Container name** | `digiserver-v2` | | **Exposed port** | `5000` (internal — proxied by Caddy) | | **Mapped port** | `5000:5000` (for direct dev access) | | **Entrypoint** | `docker-entrypoint.sh` (init DB → gunicorn) | | **Workers** | 4 gunicorn workers, 120s timeout | **Volumes (persistent data):** | Host path | Container path | Purpose | |-----------|---------------|---------| | `./data/instance` | `/app/instance` | SQLite database | | `./data/uploads` | `/app/app/static/uploads` | Media uploads | > **Code is baked into the Docker image** — see [Rebuild](#-rebuild-after-code-changes) below. ### **Container 2: caddy (Reverse Proxy)** | Property | Value | |----------|-------| | **Image** | `caddy:2-alpine` | | **Container name** | `digiserver-caddy` | | **HTTP** | `8080 → 80` (inside container) | | **HTTPS** | `8443 → 443` (inside container) | | **Admin API** | `2019` (internal, for dynamic reloads) | **Volumes:** | Host path | Container path | Purpose | |-----------|---------------|---------| | `./data/Caddyfile` | `/etc/caddy/Caddyfile:rw` | Caddy config (rewritable by Flask) | | `./data/caddy-data` | `/data` | Let's Encrypt certs & keys | | `./data/caddy-config` | `/config` | Caddy JSON config | | `./data/caddy-logs` | `/var/log/caddy` | Access logs | --- ## 🚀 Full Automated Deployment ```bash ./deploy.sh ``` This runs the complete workflow: 1. Creates `data/` directories (`instance`, `uploads`, `caddy-*`) 2. Starts containers (`docker compose up -d`) 3. Initialises database and admin user 4. Runs all database migrations 5. Enables HTTPS via Flask Admin 6. Validates Caddy configuration 7. Prints access URLs and credentials --- ## 🔧 Deployment Steps (Manual) ### **Step 1: Build & Start** ```bash docker compose up -d ``` - Builds Flask app image (layer cached) - Creates `digiserver-network` bridge - Starts `digiserver-app`, then `caddy` ### **Step 2: Database Initialization** (docker-entrypoint.sh) On container start the entrypoint automatically: 1. Creates required directories 2. Checks for existing `dashboard.db` 3. If absent — creates tables and seeds admin user 4. Starts Gunicorn (4 workers, 120s timeout) ### **Step 3: Run Migrations** ```bash docker compose exec -T digiserver-app python /app/migrations/.py ``` Key migrations: - `add_https_config_table.py` — HTTPS settings table - `add_player_user_table.py` — Player user management - `add_email_to_https_config.py` — Email field - `migrate_player_user_global.py` — Global settings - `add_url_to_content.py` — Web link support - `add_deployment_fields_to_player.py` — Deployment tracking ### **Step 4: Configure HTTPS** Via Admin UI (recommended): 1. Go to **Admin → HTTPS Config** 2. Enter hostname, domain, email, IP, port 3. Caddy auto-provisions a Let's Encrypt certificate Via CLI: ```bash docker compose exec -T digiserver-app python /app/https_manager.py enable \ ``` ### **Step 5: ProxyFix Middleware** (app/app.py) Flask extracts real client info from Caddy headers: - `X-Forwarded-For` → Real client IP - `X-Forwarded-Proto` → Protocol (http/https) - `X-Forwarded-Host` → Original hostname - `X-Forwarded-Port` → Original port --- ## 🔄 Rebuild After Code Changes Because the application code is baked into the Docker image, update it with: ```bash # 1. Rebuild the image docker build --no-cache -t digiserver-v2-digiserver-app . # 2. Replace the running container docker stop digiserver-v2 && docker rm digiserver-v2 docker compose up -d digiserver-app ``` **Quick test (no rebuild)** — copy files into the running container: ```bash docker cp digiserver-v2:/app/ docker exec digiserver-v2 pkill -HUP -f gunicorn ``` --- ## 🌐 Network Migration When the server moves to a different network / IP: ```bash ./migrate_network.sh 10.55.150.160 # Optional: ./migrate_network.sh 10.55.150.160 digiserver-secured ``` This regenerates SSL certificates, updates the database HTTPS config, and restarts both containers. --- ## 📂 Directory Structure ``` digiserver-v2/ ├── app/ (Flask application code) │ ├── app.py (App factory) │ ├── blueprints/ (Route definitions) │ ├── models/ (SQLAlchemy models) │ ├── templates/ (Jinja2 templates) │ ├── static/uploads/ (Media files on disk) │ └── utils/ (Helpers) ├── data/ (PERSISTENT — survives restarts) │ ├── instance/dashboard.db (SQLite database) │ ├── uploads/ (Media files) │ ├── Caddyfile (Caddy config) │ ├── caddy-data/ (Let's Encrypt certificates) │ ├── caddy-config/ (Caddy JSON config) │ └── caddy-logs/ (Access logs) ├── migrations/ (One-shot DB scripts) ├── old_code_documentation/ (Legacy Nginx files, etc.) ├── docker-compose.yml (Service definitions) ├── Dockerfile (Flask image build) ├── deploy.sh (Full automated deploy) ├── migrate_network.sh (Re-config after IP change) └── docker-entrypoint.sh (Container startup) ``` --- ## 🛠️ Common Commands ### **Containers** ```bash docker compose up -d # Start all services docker compose down # Stop all services docker compose restart # Restart all docker compose restart caddy # Restart only Caddy ``` ### **Logs** ```bash docker compose logs -f # Follow all docker compose logs -f digiserver-app # Flask only docker compose logs -f caddy # Caddy only docker compose logs --tail=50 digiserver-app ``` ### **Status** ```bash docker compose ps docker ps --format="table {{.Names}}\t{{.Status}}" ``` ### **Database** ```bash docker compose exec digiserver-app sqlite3 /app/instance/dashboard.db docker compose exec digiserver-app cp /app/instance/dashboard.db \ /app/instance/dashboard.db.backup ``` ### **Caddy** ```bash docker exec digiserver-caddy caddy validate --config /etc/caddy/Caddyfile docker exec digiserver-caddy caddy reload --config /etc/caddy/Caddyfile ``` --- ## 🔒 HTTPS / SSL Caddy automatically provisions Let's Encrypt certificates when a public domain is configured. For development with self-signed certificates: ```bash bash generate_nginx_certs.sh 192.168.0.121 365 docker compose restart caddy ``` > **Note:** `generate_nginx_certs.sh` has been moved to `old_code_documentation/` but still works. --- ## 🐛 Troubleshooting ### **Containers not starting?** ```bash docker compose logs docker stats ``` ### **App not responding?** ```bash docker compose ps curl http://localhost:5000/ # Bypass Caddy, hit Flask directly docker compose logs -f digiserver-app ``` ### **Caddy / HTTPS issues?** ```bash docker exec digiserver-caddy caddy validate --config /etc/caddy/Caddyfile ls -la ./data/caddy-data/certificates/ docker compose restart caddy ```