Self-Hosting Guide

Run your own Thumper-Run node: your users, your repositories, your keys, on your hardware. A node is a small fleet of cooperating processes, not a single container — the end-to-end encryption root runs isolated from the web server on purpose. This page explains what a node is; the per-platform runbooks below carry the exact commands.

Prerequisites

  • A Linux host — Ubuntu 24.04, Debian 12, Fedora 40 or newer; 4 vCPU, 8 GB RAM, 40 GB disk for the community node. macOS and Windows hosts work for development through Docker Desktop or WSL2.
  • Docker Engine 24+ with Compose v2, or Podman 5 — until the single-binary thumper-node installer ships.
  • A DNS name with ports 80 and 443 reachable — TLS is required for OIDC redirects and encrypted WebSocket sync.
  • PostgreSQL 16 with the pgsodium extension — the thumperai/postgres-pgsodium image, or your own instance with the extension installed.
  • S3-compatible object storage — a bucket at your provider, or the bundled store on the same host.

Editions & licence

The self-hosted community edition is free software under the GNU Affero General Public License v3. It includes end-to-end encryption, sign-in (OIDC, passkeys, browser sign-in key), repositories, the catalog, publishing, sync and federation. It does not include content moderation, upload screening, signed evidence (franking), security advisories or the audit anchor — those ship in the business and managed editions. Uploads and repositories on a community node are not screened; the operator is responsible for what the node hosts.

CapabilityCommunityBusinessManaged
End-to-end encrypted private projects (Mode-5)YesYesYes
OIDC sign-in, passkeys, browser sign-in keyYesYesYes
Repositories, catalog, publishing, sync, federationYesYesYes
Moderation queue, DMCA, upload screening, ClamAVNoYesYes
Franking, security advisories, audit anchorNoYesYes
Billing, marketplace payouts, managed cloud walletNoNoYes
Every node reports its edition and whether it screens content at GET /version and GET /api/v1/client-config (the node block), and links to its own source code as the AGPL requires.

Runbooks by platform

One runbook per platform, all with the same twelve steps (prerequisites, install, configure, first start, key ceremony, sign-in, verify, connect a client, upgrade, backup, uninstall, troubleshooting). They live in the repository under docs/runbooks/selfhost/.

PlatformInstall pathRunbook
Linux with Docker Compose or PodmancomposeLINUX_DOCKER_COMPOSE.md
Linux with systemd (single-binary installer)thumper-node bundleLINUX_SYSTEMD.md
macOS (Docker Desktop, OrbStack)composeMACOS_DOCKER_DESKTOP.md
Windows 11 (WSL2)compose or bundle in WSL2WINDOWS_WSL2.md
Kubernetes (k3s, kind, managed)plain manifestsKUBERNETES.md
Raspberry Pi 5 and arm64 boardsbundle or composeRASPBERRY_PI_ARM64.md
NAS (Synology, Unraid, TrueNAS SCALE)compose via the appliance UINAS_SYNOLOGY_UNRAID.md
Cloud VPS (Hetzner, DigitalOcean, Vultr, Lightsail, GCP, Azure)bundleCLOUD_VPS.md
Air-gappedoffline bundleAIRGAPPED.md
Upgrade and rollback / Backup and restoreallUPGRADE_AND_ROLLBACK.md, BACKUP_RESTORE.md
The single-binary installer and the community compose profile are in progress. Until they ship, the Linux compose runbook uses the full fleet file docker/docker-compose.mode5.yml and marks the steps that still depend on unshipped pieces.

What a node runs

The web server never holds the encryption root or the session-signing root key. Those live in separate processes with their own users and sockets; the root broker has no network at all. This is what a community node runs.

ServiceImagePurpose
webthumperai/tr-web-shell (community build)SSR app, API, sync relay
migratethumperai/tr-db-migrate (same tag)schema migrations; runs before the web on every upgrade
postgresthumperai/postgres-pgsodiumdatabase with pgsodium
rauthyghcr.io/sebadob/rauthy (pinned)OIDC identity provider
objstore, lakefsrustfs or external S3; lakeFSuploads, screenshots, repository blobs
general-biscuit-signerthumperai/general-biscuit-signersession and capability token signing
mode5-root-broker, field-key-issuer, recipient-registrarthumperai/tr-mode5-*end-to-end encryption root and field keys (broker: no network, local state)
account-*thumperai/tr-account-*sign-in binding, browser sign-in key, E2EE account enrollment
caddycaddyTLS, static caching, WebSocket upgrade
screenshot-renderer (optional)browserless/chromelisting screenshot capture

Environment Variables

The web server reads about a hundred variables; the complete list with tiers (required, recommended, advanced, business-only, managed-only) is generated from the source into docs/generated/env.md and .env.example, and a contract test keeps them in sync. These are the ones a community node cannot boot or sign in without.

VariablePurpose
TR_EDITIONself-hosted-community — must match the compiled edition or the server refuses to start
TR_PUBLIC_URLthe origin your users open; canonical URLs, sign-in redirects and the node identity derive from it
TR_NODE_NAMEname shown in clients' node picker and the connection popover
DATABASE_URL, MIGRATION_DATABASE_URLruntime and migration-owner roles (separate credentials)
RAUTHY_URL, RAUTHY_CLIENT_ID, RAUTHY_REDIRECT_URIOIDC provider and the client registered for this node
S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY (+ secret file), S3_REGIONobject storage
TR_ENROLL_CHALLENGE, TR_VALIDATE_JWT_AUDboot secrets; the server refuses to start without them
RELAY_ADMIN_SECRET, INITIAL_RELAY_ADMIN_EMAILoperator console secret and the first operator account
TR_SINGLE_USER_E2EE_ENABLED, TR_ORG_E2EE_ENABLED, TR_PRIVATE_E2EE_ENABLEDturn on end-to-end encrypted projects (the Mode-5 fleet must be running)
Sessions are Biscuit tokens signed by the separate signer process; there is no SESSION_SECRET. Secrets belong in files referenced by the compose secrets: block, never inline in .env.

SSL Certificates

SSL is required for OIDC redirects and secure WebSocket sync. Choose your method.

The easiest option. Use Caddy or Certbot as a reverse proxy.

bash
# Install Caddy
sudo apt install caddy
# Caddyfile (auto-provisions TLS)
thumper.example.com {
reverse_proxy localhost:3000
}

Caddy automatically provisions and renews Let’s Encrypt certificates.

OIDC (Rauthy)

Thumper-Run uses Rauthy as its OIDC identity provider. Any OIDC provider that issues the expected claims should work; Rauthy is the one we test.

Initial Setup

bash
# Provision the OIDC client for Thumper-Run
python3 scripts/rauthy-provision-client.py \
--rauthy-url http://localhost:8080 \
--client-name "Thumper Run" \
--redirect-uri https://thumper.example.com/auth/callback

The script prints the client id for RAUTHY_CLIENT_ID and writes the client secret; keep the secret in a file referenced by the compose secrets block.

The redirect URI registered in Rauthy must equal TR_PUBLIC_URL + /auth/callback. Never commit client secrets to version control.

Monitoring

Logs

View logs from all services.

bash
# All services
docker compose -f docker/docker-compose.mode5.yml logs -f
# Web server only
docker compose -f docker/docker-compose.mode5.yml logs -f web
# Set log level via RUST_LOG
RUST_LOG=debug docker compose -f docker/docker-compose.mode5.yml up web

Health Check

The web server exposes a health endpoint.

bash
curl -fsS https://node.example.org/readyz
curl -fsS https://node.example.org/version | jq .
# {"edition": "self-hosted-community", "api_version": 1, "source_url": "...", ...}
curl -fsS https://node.example.org/api/v1/client-config | jq .node

Updating

A migration is a hard dependency: the migrator from the new release must finish before the new web starts. Migrations are forward-only; rollback means the previous web binaries against the current schema.

bash
git fetch --tags && git checkout <new tag>
docker compose -f docker/docker-compose.mode5.yml pull
# 1. migrate first — must exit 0
docker compose -f docker/docker-compose.mode5.yml up migrate
# 2. then the web and sidecars
docker compose -f docker/docker-compose.mode5.yml up -d web
# 3. verify
curl -fsS https://node.example.org/version && curl -fsS https://node.example.org/readyz

Full procedure, including the single-binary installer and Kubernetes: docs/runbooks/selfhost/UPGRADE_AND_ROLLBACK.md.

Troubleshooting

ProblemCauseFix
502 Bad GatewayWeb server not readyWait 30s for startup; check docker logs web
OIDC redirect errorMismatched redirect URIRAUTHY_REDIRECT_URI and the Rauthy client must both be TR_PUBLIC_URL + /auth/callback
DB connection refusedPostgres not startedCheck docker ps for the postgres container; verify DATABASE_URL and that pgsodium loaded
WebSocket failsMissing proxy upgradeAdd WebSocket upgrade headers in nginx/Caddy config
SSL certificate errorDNS not propagatedVerify DNS with dig thumper.example.com; wait for propagation
Server exits: TR_EDITION does not match the compiled editionImage built for another editionUse the community image, or fix TR_EDITION
E2EE project cannot be createdMode-5 fleet not running or issuer socket owned by rootRe-run the ceremony steps; check client-config.node.e2ee

Key Takeaways

  • A node is a small fleet: web, migrator, Postgres with pgsodium, Rauthy, object storage, the biscuit signer, the Mode-5 encryption processes and the account services
  • Community edition = AGPL-3.0, with E2EE and sign-in, without moderation, screening, franking or advisories — uploads and repos are unscreened
  • Set TR_EDITION, TR_PUBLIC_URL, TR_NODE_NAME, the database, Rauthy and S3 variables, and the two boot secrets
  • Export the encryption root key off the host during the ceremony; losing it loses every E2EE project
  • Upgrade = migrate first, then the web; migrations are forward-only
  • Every node publishes its edition, screening status and source link at /version and /api/v1/client-config

Advanced Reading

The full plan, edition boundary and the single-binary installer design: docs/plans/SELF_HOSTED_NODE_PLAN_2026-09-13.md; licensing: docs/legal/LICENSING.md.