Deployment Model
How a beacon is deployed — the CLI, the release images, and the stack it runs.
The Beacon CLI is the supported way to deploy and operate a beacon. It owns the Docker Compose files, secrets, and ingress configuration so you don't have to. This page explains what actually runs, so the rest of the deploy docs make sense.
The CLI drives everything
You never write Compose files or run docker directly. beacon create (or the
guided beacon wizard) scaffolds a deployment directory and beacon up
brings it online. Day-2 operations — upgrade, restart, status, logs — all go
through the CLI too.
curl -fsSL https://beacon-mc.io/install.sh | sh # install the CLI
beacon # create + deploy ~/.beacon
beacon status # health probe
beacon upgrade 0.31.1 --yes # update laterGame operations live in the dashboard
The CLI is scoped to host operations (deploy, update, start, stop, inspect).
People, invites, the allowlist, backups, server settings, and mods are
managed in the web dashboard — open it with beacon admin. See
Managing your beacon.
What runs in the stack
A beacon is a small set of containers on a private Compose network:
| Service | What it is | Exposed? |
|---|---|---|
minecraft | The game server (itzg image; Paper by default) | Public on 25565 |
web | The Next.js operator dashboard | Internal only |
admin-rpc | Privileged backend (Docker socket + RCON-write) | Internal only |
tailscale or caddy | The ingress proxy that fronts the dashboard | See Networking |
The privilege boundary is deliberate: the public-facing web app never gets
the Docker socket or RCON-write — every privileged action passes through
admin-rpc. That's why you reach the dashboard through an ingress proxy rather
than by exposing internal ports. See Ports & Access.
Release images
Beacon's images are public on GHCR — no GitHub token required:
ghcr.io/thoughts-on-things/beacon/webghcr.io/thoughts-on-things/beacon/admin-rpc
beacon up pulls these at the version pinned by BEACON_VERSION and recreates
the stack. The minecraft, tailscale, and caddy services come from
upstream images. Images ship for linux/amd64 and linux/arm64.
Requirements
- A 64-bit Linux host (amd64 or arm64) with Docker Engine and Docker Compose v2.24+.
- Node.js 20+ to run the
beaconCLI. - One inbound TCP port per beacon for Minecraft (
25565for the first). - For custom-domain ingress, inbound TCP
80+443. For Tailscale, nothing extra.
New to hosting? Follow the end-to-end Hosting on a VPS walkthrough, which covers provisioning the host as well.
What beacon create writes
In the deployment directory (~/.beacon by default), the CLI generates:
.env— generatedMC_RCON_PASSWORD,ADMIN_RPC_TOKEN,BEACON_SESSION_SECRET, the pinnedBEACON_VERSION, the uniqueBEACON_INSTANCE/COMPOSE_PROJECT_NAME, andCOMPOSE_PROFILESfor the chosen ingressdocker-compose.ymlanddocker-compose.release.ymltailscale-serve.jsonandCaddyfile(the inactive one is harmless).gitignoreand a short project README
These are CLI-managed. Edit .env for settings the CLI exposes, but let
beacon upgrade / beacon restart re-render the compose files — they're
regenerated from the CLI's bundled templates so an older install picks up new
service wiring. See Configuration.
Multiple beacons on one host
Run one beacon create per directory. Each gets a unique Docker project,
container names, and Minecraft port (auto-assigned from 25565 up). Bare
beacon opens a TUI to switch between registered beacons; scripts use
--dir <path>.
beacon create ~/beacons/survival --yes \
--app-url https://survival.<tailnet>.ts.net \
--tailscale-auth-key tskey-... \
--mc-image itzg/minecraft-server:java25 --mc-version 26.1.2
beacon create ~/beacons/creative --yes \
--app-url https://creative.<tailnet>.ts.net \
--tailscale-auth-key tskey-... \
--mc-image itzg/minecraft-server:java25 --mc-version 26.1.2