Skip to content

Run in Production

automoto edited this page Aug 1, 2026 · 1 revision

Run in Production (basic)

This page gets a single ggscale instance running for real traffic. It covers two paths that share the same server: Docker Compose with your own secrets and TLS in front, or the ggscale-server binary against a remote Postgres. Pick one.

Backup, upgrade, and monitoring get their own pages later. This page is the minimum to serve players safely.

What the server needs

  • Postgres. One database. The server applies its migrations on startup, so you point it at an empty database and it builds the schema.
  • A place to run one Go binary. The server listens on plain HTTP (default :8080). Put TLS in front of it (see below).
  • Secrets. Outside production the server generates signing keys into a server_secrets table on first boot, so local runs need no secret config. In production you set the important ones yourself, because a generated key that lives only in one database is hard to rotate and share.

Set the production environment

Set ENV=production. The server then refuses to boot unless the hardening config is present, so a misconfiguration is caught at startup, before the server takes traffic. The required set is:

  • DATABASE_URL and a separate DB_MIGRATE_URL (the migrate URL runs DDL and must differ from the app login).
  • APP_REGION set to an explicit region name, not local.
  • JWT_SIGNING_KEY and EMAIL_VERIFY_SIGNING_KEY.
  • CORS_ALLOWED_ORIGINS listing your real origins, with no *.
  • CONTROL_PANEL_BASE_URL on https://, CONTROL_PANEL_COOKIE_SECURE=true, and CONTROL_PANEL_BOOTSTRAP_TOKEN_FILE.
  • METRICS_AUTH_TOKEN, or METRICS_AUTH_DISABLED=true to serve /metrics open on purpose.

Generate each secret with a strong random value:

openssl rand -hex 32

The full list of variables and defaults is in Configuration Reference.

Path A: Docker Compose

Run the published image buildwrangler/ggscale:latest behind a TLS-terminating reverse proxy.

  1. Write a Compose file with the server, your Postgres (or point at a managed one), and your secrets. Keep secrets out of the image; pass them as environment or mount them with the <NAME>_FILE convention.
  2. Put a reverse proxy in front (Caddy, nginx, or a cloud load balancer) that terminates TLS and forwards to the server on :8080. If the proxy sets a forwarded-IP header, allow it with TRUSTED_PROXY_HEADER and TRUSTED_PROXY_CIDRS so rate limits see the real client IP.
  3. Start the stack. The server runs its migrations, then serves traffic.

Path B: The binary against remote Postgres

Run ggscale-server directly on a host, pointed at a managed Postgres.

  1. Provide the same production environment as above. Point DATABASE_URL at the app login role and DB_MIGRATE_URL at a role that can run DDL.
  2. Set MIGRATIONS_DIR to the migrations directory shipped with the binary. The container image already sets /migrations; a bare binary needs the path to its copy.
  3. Start the binary under a process manager (systemd or similar). Front it with a TLS-terminating proxy, the same as Path A.

First-run setup

The server writes a one-time bootstrap token on first boot. In production point CONTROL_PANEL_BOOTSTRAP_TOKEN_FILE at a file path, read the token from there, and complete setup at https://<your-host>/v1/control-panel/setup. See Onboarding a New Game for the walkthrough.

Email

Local stacks catch mail in Mailpit. For real signup and invite email, set SMTP_ADDR, SMTP_USER, SMTP_PASSWORD, SMTP_TLS, and MAIL_FROM to your SMTP relay. See Configuration Reference.

Next

Backup, upgrade, and monitoring pages come later. Until then, back up Postgres on your own schedule; it holds the whole system, including the generated secrets.

Clone this wiki locally