Simple, beautiful game servers. Ghost is a dedicated game server platform you can read, fork, and self-host. Spin one up in seconds — Docker, SSH, and firewall rules handled for you.
app/ Next.js App Router — UI, API, Better Auth
lib/ server-side libs (db, redis, hetzner, agent helpers, workflows)
protocol/ Zod schemas + signing canonicalization shared with the agent
agent/ Bun-built TypeScript agent (compiled to a Linux binary)
prisma/ schema + migrations
games/ per-game compose generators
-
Clone the repo
git clone https://github.com/haydenbleasel/ghost.git cd ghost -
Install dependencies
bun install
-
Provision the backing services
- Postgres via Neon — grab both the pooled and direct connection strings.
- Redis via Vercel KV or Upstash.
- Blob storage via Vercel Blob — used to host the agent binary.
-
Configure environment variables
cp .env.example .env.local
Fill in the values from step 3. Generate
BOOTSTRAP_JWT_SECRETandBETTER_AUTH_SECRETwithopenssl rand -hex 32. -
Run database migrations
bun migrate
-
Enable Vercel Deployment Protection bypass (preview deploys only)
In your Vercel project settings, enable Deployment Protection → Protection Bypass for Automation. The generated value is auto-injected as
VERCEL_AUTOMATION_BYPASS_SECRETso Hetzner agents can punch through the auth wall on callbacks. -
Deploy to Vercel
vercel deploy
-
Sign in and bake your golden image
Open the deployed app, sign in, save a Hetzner Cloud token on
/dashboard/account/backend, and click Build snapshot. Baking takes ~10–15 min.
Note
New Hetzner Cloud accounts are capped at 5 servers per project until the account is verified. Provisioning fails with resource_limit_exceeded once you hit it — request a limit increase from Hetzner support.
Each game lives in its own folder under games/. To add one:
-
Create a folder —
games/<your-game>/with three files:install.ts— exportsdockerImage(the upstream image tag) andbuild<Game>Compose(config, settings)(returns the compose YAML string).settings.ts— exports a settings schema viadefineSettings(...)describing the per-server options.index.ts— exports the game definition (id,name,description,image,dockerImage,ports,requirements,settings,buildCompose, etc.). Use an existing folder likegames/minecraft/as a template.
-
Register it in
games/index.ts— import your game and add it to thegamesarray. -
Redeploy and rebuild the snapshot — the snapshot's
docker pulllist is derived fromgames[].dockerImage, so once you redeploy, click Build snapshot again to bake the new image into the golden image.
bun dev— Next dev server (turbopack)bun run build— prisma generate + next build
