Panel and Daemon deployment
This page starts with a single Ubuntu test host. Nginx terminates Panel HTTPS, Panel listens on loopback, a separate TLS Gateway accepts Daemon control connections, and the Daemon runs with rootless Docker. Production replicas require PostgreSQL, Redis and a shared Artifact Store; do not use the test stack's SQLite and local-storage choices for multiple Panel replicas.
One-command test stack
Prepare an Ubuntu 26.04 x86-64 host with at least 2 CPU, 4 GiB memory and 20 GiB free disk. Allow inbound TCP 22, 80, 443 and 9443. Store the root SSH key inside the development checkout, with mode 0600, then run from the checkout root:
gamex-references/deployment/test-stack/deploy.sh \
--host <public-ip> \
--identity-file <absolute-path-to-key-inside-the-checkout> \
--yesThe script builds the current Panel and Daemon, configures Nginx and a short-lived public IP certificate, installs rootless Docker, initializes the Panel and enrolls one Daemon. Generated test administrator material is downloaded to the Git-ignored gamex-references/docs/private/ directory with mode 0600; do not copy it into tickets or documentation.
Run the read-only verification independently:
gamex-references/deployment/test-stack/deploy.sh \
--host <public-ip> \
--identity-file <absolute-path-to-key-inside-the-checkout> \
--verify-onlyRequire all systemd units to be active, rootless Docker to pass its check, Gateway certificate verification to succeed and the Daemon status to report controlConnected as true.
Enroll additional Daemons
In Daemons, create a short-lived one-time enrollment link for the intended host. Install gamex and gamex-daemon on that host and run:
sudo gamex configure
sudo gamex doctor
sudo systemctl status gamex-daemon@gamex.service
sudo curl --unix-socket /run/gamex-daemon/admin.sock http://localhost/statusPaste the complete enrollment link only into the hidden prompt. Do not place it in a command argument or shell history. Repeat with a different link and a unique Daemon name for every host. Before placing a Workspace, confirm the expected architecture, CPU, memory, disk, rootless Docker socket and online state in Daemons.
Gateway and trust rotation
Generate private Gateway material for a production deployment outside the Web Setup flow:
npm --prefix gamex-panel/backend run gateway:bootstrap -- \
--control-url wss://panel.example.com:9443/api/v1/daemon/connectKeep the generated key at mode 0600. Give every live Gateway replica a unique DAEMON_GATEWAY_INSTANCE_ID. During CA or leaf rotation, first deploy a bundle containing both old and new roots, canary the new leaf, reconnect one Daemon, roll the remaining replicas, and remove the old root only after every Daemon is healthy. Restore the old leaf while the overlap bundle remains active if the canary fails.
Production acceptance
- The load balancer uses
GET /api/health/ready, not the liveness endpoint. - Panel replicas share one deployment identity, PostgreSQL, Redis and Artifact Store but have unique Gateway instance IDs.
- The Panel port is private; only HTTPS and the mTLS Gateway are public.
- System Docker stays disabled on Daemon hosts; the Daemon uses the dedicated rootless socket.
- At least one Panel-only Chat succeeds before any Daemon is enrolled, then a harmless Workspace read succeeds on each enrolled Daemon.
For pre-release deployment and incident procedures, continue with Deployment, rollback and recovery.