Docker Deployment
Running Zonal in Docker is the recommended approach for production church IT environments — it isolates the controller, makes upgrades a one-command operation, and works on any Linux server.
Prerequisites
- Docker Engine 24+ and Docker Compose v2
- A Linux host (Ubuntu 22.04 LTS recommended)
- Your
SPL_LICENSE_KEYfrom your confirmation email
docker-compose.yml
services:
controller:
image: ghcr.io/steeplestack/zonal:latest
restart: unless-stopped
ports:
- "4000:4000" # Dashboard
- "1883:1883" # MQTT (monitors connect here)
environment:
SPL_LICENSE_KEY: ${SPL_LICENSE_KEY}
SPL_DB_PATH: /data/zonal.db
volumes:
- zonal_data:/data
# Optional: MQTT broker if you prefer an external one
# mosquitto:
# image: eclipse-mosquitto:2
# ports: ["1883:1883"]
volumes:
zonal_data:Environment file
Create a .env file next to your docker-compose.yml:
SPL_LICENSE_KEY=SPL-XXXX-XXXX-XXXX-XXXXStarting the controller
docker compose up -d
docker compose logs -f controllerThe dashboard is available at http://<your-server-ip>:4000 within a few seconds of startup.
Upgrading
docker compose pull
docker compose up -d
docker image prune -fConfiguration and historical data are stored in the zonal_data volume and are not affected by upgrades.
Reverse proxy with HTTPS (recommended)
For production deployments, put the dashboard behind nginx with a Let's Encrypt certificate so you can access it securely from anywhere.
services:
controller:
image: ghcr.io/steeplestack/zonal:latest
restart: unless-stopped
expose: ["4000"]
environment:
SPL_LICENSE_KEY: ${SPL_LICENSE_KEY}
VIRTUAL_HOST: zonal.yourchurch.org
VIRTUAL_PORT: "4000"
LETSENCRYPT_HOST: zonal.yourchurch.org
LETSENCRYPT_EMAIL: [email protected]
volumes:
- zonal_data:/data
nginx-proxy:
image: nginxproxy/nginx-proxy:alpine
ports: ["80:80", "443:443"]
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- certs:/etc/nginx/certs
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
acme-companion:
image: nginxproxy/acme-companion
volumes_from: [nginx-proxy]
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- acme:/etc/acme.sh
volumes:
zonal_data:
certs:
vhost:
html:
acme:Firewall rules
| Port | Protocol | Purpose | Expose to |
|---|---|---|---|
| 4000 | TCP | Dashboard / API | LAN or reverse proxy only |
| 1883 | TCP | MQTT (monitors) | LAN only |
| 8883 | TCP | MQTT over TLS (optional) | LAN or internet |
Health check
curl http://localhost:4000/api/health
# {"status":"ok","version":"2.3.1","licensed":true}