The public demo's deployment (docs/website/DEMO_MODE.md §7, §10 step 5): - deploy/demo/docker-compose.yml: the app and its database only, DEMO_MODE on, a /status healthcheck, the fixture mounted for seed:demo, MODULES read from state/modules.env so the workflow never edits the .env with secrets. - deploy/demo/.env.example: every variable the host needs, including BOT_INTERNAL_KEY (the app refuses to start in production without it) and MODULE_SOURCE_HOSTS (a fresh database's install allowlist). - deploy/demo/seed.json: the four logins, settings, two posts, a wiki page, a published "Server greeting" event on a Rust console step, the rig's server link and demo-player's Steam link; secrets as "$env:NAME". - deploy/demo/rig.mjs: plan (latest Rust bundle + newest Module-Rust on the same protocol, keeping the previous set when none matches), restore (kill, write a changed bundle, delete + unpack demo-baseline.tar.gz, start), baseline (power stop saves the world, DM22; compress, rename, start) and smoke (the site, then the rig reporting in), on the Pterodactyl client API. - .gitea/workflows/demo-wipe.yml: every 2 h on the hour UTC, on a push to deploy/demo/, and by hand; rig first, then down -v / pull / up / seed. - .gitea/workflows/demo-baseline.yml: by hand only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
deploy/demo — demo.runicgateway.com
The public demo site: the normal image with DEMO_MODE=true, wiped every two hours together
with its Rust server. Design of record: docs/website/DEMO_MODE.md.
| File | What it is |
|---|---|
docker-compose.yml |
The app and its database. No bot and no ntfy: the demo sends nothing outward (§5) |
.env.example |
Every variable the host's .env needs, with what each one is for |
seed.json |
The fixture seed:demo writes after every wipe: the four logins, settings, content, and the Rust module's server link and Steam link (§7.3). Passwords and credentials are "$env:NAME" references to .env |
rig.mjs |
Versions (plan), the rig restore (restore), the baseline capture (baseline) and the smoke check (smoke), against the Pterodactyl client API (§7.2, §7.5) |
Two workflows drive it, both on the demo-site runner:
demo-wipe.yml: every 2 hours on the hour (UTC), on a push tomainthat changes this directory, and by hand. Versions, then the rig, then the site, then a smoke check.demo-baseline.yml: by hand only. It captures the rig's current state asdemo-baseline.tar.gz, which every wipe restores.
One-time host setup
- The
demo-siterunner in host mode on the demo host, with Docker and Compose, andnodeon thePATH(foractions/checkout). The host must reachgitea.whitlocktech.com, the Pterodactyl panel and the rig's sidecar port. sudo mkdir -p /opt/demo.runicgateway.com, owned by the runner's user (or the runner runs as root). To use another path, set theDEMO_DIRActions variable.- Copy
.env.exampleto/opt/demo.runicgateway.com/.envand fill every blank. Generate secrets on the host, e.g.openssl rand -hex 32. The file never leaves the host. - Log the host in to the registry if the images are not public:
docker login gitea.whitlocktech.com. - Point the external reverse proxy at
<host>:DEMO_HOST_PORT(default 3000). - Run Demo wipe by hand. The first run finds no baseline, so it leaves the rig as it is and starts it.
Then set the demo default set up through the site: the permission groups, a few NPCs, a clan. Run Demo baseline while nobody else is changing anything. Every later wipe returns the rig to that.
The panel URL and the rig's server identifier default to http://192.168.0.12 and 6eb9d621
(rust-oxide). Override them with the PTERODACTYL_URL and PTERODACTYL_SERVER Actions
variables. PTERODACTYL_CLIENT_KEY is the demo subuser's key, an Actions secret.
What the wipe keeps on the host
state/ in the deploy directory:
bundle.json: the Rust bundle last written onto the rig. A new bundle is written only when this differs.modules.env:MODULES=rust@<version>=<manifest>, the newest Module-Rust release on the bundle's protocol. When no release matches a new bundle yet, the wipe keeps this file and the rig's bundle as they were and warns (§7.5).plan.json: this cycle's decision, fromplantorestore.
modules/ keeps the unpacked module between wipes. down -v drops the database and the uploads,
never this directory.