Skip to content

Operations

Terminal window
docker compose pull && docker compose up -d

Database migrations run on every start and are safe to repeat, so an upgrade is a pull, not a runbook.

TEAMHUD_VERSION in .env picks which server image you follow:

Value Moves when Use it for
stable (default) a release is promoted. None has been yet, so until then set edge or the pull fails with manifest unknown production
edge every change we merge trying things early; expect breakage
sha-<12 chars> never pinning a known-good build, and rolling back to one

Pinning turns an upgrade into a deliberate edit. To roll back, set the previous sha-… and docker compose up -d.

The other images (Postgres, auth, storage, media server) are pinned in docker-compose.yml. Read their release notes before bumping a major version.

backup.sh writes a dated, compressed dump of the whole database to /var/backups/teamhud (readable by root only), plus a tarball of the storage-data and recording-media volumes with the same timestamp, and keeps 14 days. Install the nightly timer once, as root, and prove it runs now rather than tomorrow:

Terminal window
./backup.sh install
systemctl start teamhud-backup.service && ls -la /var/backups/teamhud

It covers accounts, organizations, messages, file metadata, and the uploaded files and recordings on those two volumes. It does not cover itself: the dumps sit on the same disk they protect. Copy them off the box, or turn on your provider’s machine-level backups. Files in S3-compatible storage (see below) are not in the tarball either.

A backup nobody has restored is a hope. Restore into a scratch database, compare a few row counts against the live one, then drop it:

Terminal window
docker compose exec db psql -h 127.0.0.1 -U supabase_admin -d postgres -c 'CREATE DATABASE restore_drill'
docker compose exec -T db pg_restore -h 127.0.0.1 -U supabase_admin -d restore_drill --no-owner --no-acl \
< /var/backups/teamhud/teamhud-<stamp>.dump
docker compose exec db psql -h 127.0.0.1 -U supabase_admin -d postgres -c 'DROP DATABASE restore_drill'

Attachments, avatars and release installers stay on a local Docker volume by default, which is what you want when the reason you self-host is that data stays in your building.

To use S3-compatible object storage instead, set the STORAGE_* block in .env (it is documented in .env.example). Two warnings:

  • Switching does not move existing files. Copy them first, or they vanish from the app.
  • STORAGE_WORKSPACE is write-once. Every object path hangs off it. Choose it once.
  • Boot log: docker compose logs server | head -50 states which optional features it found and which are off. It is the fastest check after any .env change.
  • Health: ./verify-stack.sh re-runs the full end-to-end check at any time.
  • Capacity: the thstat collector reports real CPU, memory and bandwidth. See Sizing.

gen-keys.mjs generates the database password, the login-token signing secret, the media server keys, the encryption key, and the two service keys.

  • .env is a secret. Keep it chmod 600, out of git, and out of chat.
  • Never substitute Supabase’s published demo keys. They are signed with a public secret, so anyone who recognises one can mint their own.
  • Adding a setting is one step: put it in .env and run docker compose up -d. Every supported variable is already wired into docker-compose.yml.

A server that has never been activated serves only the activation screen: sign in to TeamHUD Cloud and approve the code, or paste a key. A server that was activated and later lapses keeps running at Free limits. A key is what licenses a team to run on it.

  1. Buy a self-host licence at dashboard.teamhud.app → Billing. The key appears under Licences.
  2. Set TEAMHUD_LICENSE_KEY and TEAMHUD_LICENSE_PUBLIC_KEY in .env (both are needed), then docker compose up -d.
  3. Check GET /usage on your server to confirm the plan. The boot log does not report it.

The server renews the licence daily by itself.

By default your server serves its own terms and privacy pages at /legal/…, so your users never consent to TeamHUD’s documents while their data lives in your database. Point to your own with TEAMHUD_TERMS_URL, TEAMHUD_PRIVACY_URL and TEAMHUD_ACCEPTABLE_USE_URL, and bump TEAMHUD_LEGAL_VERSION whenever you change them to make everyone re-accept.

A small game server for team mini-games. firstboot.sh installs it unless you answer no. Turn it on or off with ENABLE_GAMES=true|false in .env, then re-run ./firstboot.sh, which adds or removes the container and its secret. Desktops list only the games your server can actually run.