Docker Compose
The project includes a Dockerfile, a docker-compose.yml and a Caddyfile.
The image is small and pure JavaScript, so it builds the same on amd64 and arm64.
It runs as an unprivileged user, has a health check, and stops cleanly within
milliseconds on docker stop.
cp example.env .env # fill in PVE_*, JWT_SECRET, … as usual
docker compose up -d --build
# first administrator (and all other helper commands) inside the container
docker compose exec panel npm run user:create -- admin@example.com 'a-long-password' --admin
- Ports: the customer panel on
3000, the admin interface only on127.0.0.1:3001of the Docker host (SSH tunnel as before). The container itself listens on all interfaces; the compose file keeps the admin port local.HOST,ADMIN_HOSTandDB_PATHare set by the compose file, whatever.envsays. - Data: the database lives in the
panel-datavolume. Back it up while the panel runs withdocker compose exec panel npm run db:backup(writes a consistent copy to/app/data/backups/), then copy it out:docker compose cp panel:/app/data/backups ./backups. - HTTPS with automatic certificates: set
PANEL_DOMAIN=panel.example.comin.env(DNS pointing at this host, ports 80 and 443 reachable) and start withdocker compose --profile https up -d --build. Caddy gets and renews a Let's Encrypt certificate and forwards to the panel, including the console's WebSockets. SetCOOKIE_SECURE=trueandPANEL_PUBLIC_URL=https://panel.example.com, and remove the3000:3000line so the panel is only reachable through Caddy. - Proxmox CA: mount your
pve-root-ca.pem(see the commented line indocker-compose.yml) and setPVE_CA_FILE=/app/certs/pve-root-ca.pem. - Updating:
docker compose up -d --buildafter replacing the files; the database is migrated at start, the volume keeps everything. - Networking: the container needs outbound access to the Proxmox API (8006) and, for single sign-on, to your identity provider. The panel host's clock (which containers share) must be right for 2FA codes.