5.7 KiB
5.7 KiB
07 · Deployment
DigiServer v2 runs as a Docker Compose stack (app + Caddy) with optional remote SSH provisioning of players.
1. Architecture
flowchart LR
subgraph Host["Docker Host"]
subgraph Net["digiserver-network"]
APP["digiserver-app\nFlask + Gunicorn :5000"]
CAD["caddy:2-alpine\n:80 / :443"]
end
VOL1["./data/instance → /app/instance\n(SQLite DBs)"]
VOL2["./data/uploads → /app/app/static/uploads"]
VOL3["./data/Caddyfile → /etc/caddy/Caddyfile"]
VOL4["./data/caddy-data → /data\n./data/caddy-config → /config"]
end
Browser["Browser"] --> CAD
CAD --> APP
APP --> VOL1
APP --> VOL2
CAD --> VOL3
CAD --> VOL4
APP -.SSH/rsync.-> Players["Remote player hosts"]
2. docker-compose.yml
Service digiserver-app
- Build:
.(Dockerfile,python:3.13-slim) - Ports:
5000:5000(direct dev access; alsoexpose: 5000) - Volumes:
./data/instance:/app/instance,./data/uploads:/app/app/static/uploads - Env:
FLASK_ENV=production,SECRET_KEY,ADMIN_USERNAME,ADMIN_PASSWORD - Healthcheck: HTTP GET
http://localhost:5000/(30s interval, 40s start) - Restart:
unless-stopped
Service caddy
- Image:
caddy:2-alpine - Ports:
8080:80,8443:443 - Volumes:
./data/Caddyfile:/etc/caddy/Caddyfile:rw,./data/caddy-data:/data,./data/caddy-config:/config,./data/caddy-logs:/var/log/caddy - Depends on: app (service started)
- Healthcheck:
wgeton port 80
3. Dockerfile
| Stage | Content |
|---|---|
| Base | python:3.13-slim |
| System deps | poppler-utils, ffmpeg, libmagic1, sudo, fonts-noto-color-emoji, LibreOffice (core/impress/writer), sshpass, openssh-client, rsync, git |
| Python | COPY requirements.txt → pip install (cached layer), then COPY . . |
| App config | FLASK_APP=app.app:create_app, FLASK_ENV=production, EXPOSE 5000 |
| User | Non-root appuser (UID 1000) with passwordless sudo limited to apt-get, install_libreoffice.sh, install_emoji_fonts.sh |
| Runtime | HEALTHCHECK (HTTP 5000), ENTRYPOINT /docker-entrypoint.sh |
4. docker-entrypoint.sh
- Create
/app/instanceand/app/app/static/uploads. - If
dashboard.dbis missing: create app +db.create_all(), then create/update the admin user fromADMIN_USERNAME/ADMIN_PASSWORD. - Start Gunicorn:
--bind 0.0.0.0:5000 --workers 4 --timeout 120 app.app:create_app('production').
5. deploy.sh (One-Shot Deployment)
1. Validate compose + project; create data/ subdirs; copy nginx configs
2. docker compose up -d + verify containers "Up"
3. Run migration scripts (add_https_config_table, add_player_user_table,
add_email_to_https_config, migrate_player_user_global,
add_original_filename_to_content)
4. Run /app/https_manager.py enable <hostname> <domain> <email> <ip> <port>
⚠ https_manager.py is NOT in the current repo — this step needs attention
5. Verify DB tables via SQLAlchemy inspector
6. caddy validate + https_manager.py status; print access URLs + default creds
6. HTTPS Setup (Caddy)
HTTPS is configured through the Admin → HTTPS Configuration page, which:
- Saves
HTTPSConfig(hostname, domain, IP, email, port, enabled). CaddyConfigGenerator.generate_caddyfile(config)picks a template:- HTTP-only →
:80reverse proxy - Domain → automatic Let's Encrypt
- IP → internal CA self-signed
- HTTP-only →
- Writes
/etc/caddy/Caddyfileand reloads Caddy viaPOST http://caddy:2019/load.
The current data/Caddyfile (HTTP mode) includes: admin API on 0.0.0.0:2019, :80 block → digiserver-app:5000, 2 GB body limit, gzip, security headers, access log.
7. verify-deployment.sh — Pre/Post-Deployment Checks
Sections checked (pass/fail/warn counters):
- git status
.env/.env.example- Docker + Compose versions +
compose configsyntax - Dockerfile best practices (HEALTHCHECK, non-root, slim base)
requirements.txtcritical packages + versions- migrations directory
- SSL cert expiry (openssl)
- Flask config (
ProductionConfig,SESSION_COOKIE_SECURE) - nginx.conf checks
- runtime container health
- security best practices
⚠ Note: the script still references
docker-compose(v1) anddigiserver-nginx— the current stack uses Compose v2 + Caddy.
8. Player Deployment Pipeline
sequenceDiagram
participant U as Admin
participant A as App
participant B as Background
participant H as Player host
U->>A: Add player (name, hostname, password/quickconnect)
A->>B: background_player_deployment()
B->>B: build/refresh staged code (PLAYER_CODE_DIR)
B->>H: sshpass + ssh test
B->>H: rsync code (or git clone/pull fallback)
B->>H: write config/app_config.json (server_ip, quickconnect, https...)
B->>H: temporary passwordless sudo
B->>H: ./install.sh && ./start.sh
B->>H: remove temp sudoers
B-->>A: player.deployment_status = 'deployed' | 'failed'
U->>A: poll /players/deployment-status
Statuses: pending → deploying → deployed | failed, with last_deployment_at/status/message persisted on the player row. Receiving player feedback also auto-marks deployment deployed.
9. Ports & Volumes Summary
| Item | Value |
|---|---|
| App port (container) | 5000 |
| App port (host, dev) | 5000 |
| Caddy HTTP | 8080 → 80 |
| Caddy HTTPS | 8443 → 443 |
| Caddy admin API | 2019 (container) |
| DB volume | ./data/instance |
| Uploads volume | ./data/uploads |
| Caddy data/config/logs | ./data/caddy-* |
Next: 08 · Workflows