052751b599
- Replace Nginx references throughout with Caddy - Update architecture diagram to show Caddy - Update container details (caddy:2-alpine, ports 8080/8443) - Update volume paths (caddy-data, caddy-config, caddy-logs) - Add rebuild guide for code changes (docker build + restart) - Add quick-test method (docker cp + pkill -HUP) - Simplify commands section (docker compose not docker-compose) - Remove Nginx-specific troubleshooting - Add Caddy validation and reload commands
301 lines
8.5 KiB
Markdown
301 lines
8.5 KiB
Markdown
# 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 <repository>
|
|
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/<name>.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 \
|
|
<hostname> <domain> <email> <ip_address> <port>
|
|
```
|
|
|
|
### **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 <local_file> digiserver-v2:/app/<path>
|
|
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
|
|
```
|