Self-Hosting Setup

~30 minAdvancedYou'll build: A running Thumper-Run instance on your VPS

In this tutorial you’ll deploy a full Thumper-Run server on your own infrastructure using Docker Compose. By the end, you’ll have a running instance with authentication, ready to accept connections from the desktop app.

Self-hosting requires managing your own backups, SSL certificates, and security updates. Make sure you’re comfortable with server administration before proceeding.

Step 1: Prerequisites

Before you begin, make sure your server meets the following requirements:

Server Requirements

  • OS — Ubuntu 22.04 LTS or newer (Debian-based recommended)
  • RAM — 8 GB for the community node (4 vCPU, 40 GB disk plus object storage)
  • Disk — 20 GB free space (more if hosting model weights)
  • Domain — a domain name pointed at your server’s IP address

Software Requirements

Install Docker Engine and the Compose plugin from your operating system’s package manager or Docker’s signed package repository. Do not pipe a downloaded installer into a shell:

bash
# After following the signed repository/package instructions for your OS
docker --version
docker compose version
Granting access to the Docker socket is effectively root-level access. Follow your operating system’s Docker documentation and do not add users to privileged groups automatically.
You’ll also need Git installed for cloning the repository. Most Ubuntu systems include it by default.

Step 2: Clone and Configure

Clone the Thumper-Run repository and set up your environment configuration:

bash
# Clone the repository
git clone https://github.com/thumper-ai/thumper-run.git
cd thumper-run
# Copy the example environment file
cp .env.example .env

Configure .env

Open .env and fill the REQUIRED block. The file is generated from the server’s own configuration reader, so every variable it lists is real:

# Edition and identity
TR_EDITION=self-hosted-community
TR_PUBLIC_URL=https://node.example.org
TR_NODE_NAME=Example Lab
# Database roles (runtime and migration owner are separate credentials)
DATABASE_URL=postgres://tr_runtime:...@postgres:5432/thumper_run
MIGRATION_DATABASE_URL=postgres://tr_migration_owner:...@postgres:5432/thumper_run
# OIDC
RAUTHY_URL=https://auth.node.example.org
RAUTHY_CLIENT_ID=<from step 4>
RAUTHY_REDIRECT_URI=https://node.example.org/auth/callback
# Object storage
S3_ENDPOINT=http://rustfs:9000
S3_BUCKET=thumper
S3_REGION=us-east-1
# Boot secrets and operator (generated below)
TR_ENROLL_CHALLENGE=<64 hex>
TR_VALIDATE_JWT_AUD=<64 hex>
RELAY_ADMIN_SECRET=<64 hex>
INITIAL_RELAY_ADMIN_EMAIL=you@example.org
# End-to-end encryption (part of the community edition)
TR_SINGLE_USER_E2EE_ENABLED=true
TR_ORG_E2EE_ENABLED=true
TR_PRIVATE_E2EE_ENABLED=true

Generate the boot secrets

Sessions are Biscuit tokens signed by a separate signer process, so there is no session secret to invent. The web server does need two boot secrets and the operator console secret; generate each with:

bash
openssl rand -hex 32 # TR_ENROLL_CHALLENGE
openssl rand -hex 32 # TR_VALIDATE_JWT_AUD
openssl rand -hex 32 # RELAY_ADMIN_SECRET
# Access keys, database passwords and the Rauthy client secret go in ./secrets/<name> (chmod 600),
# referenced by the compose secrets: block — never inline in .env
Never commit your .env file to version control. It contains secrets that must stay private.

Step 3: Start Services

A node is a small fleet of processes, started in order: database, migrations, then the encryption fleet, then the web. Until the community profile file ships, the full fleet definition is docker/docker-compose.mode5.yml:

bash
# 1. database, then migrations (must exit 0 before anything else starts)
docker compose -f docker/docker-compose.mode5.yml up -d postgres postgres-crypto-provision
docker compose -f docker/docker-compose.mode5.yml up migrate post-migration-db-grants
# 2. object storage and the encryption fleet (see the Mode-5 ceremony in the runbook)
docker compose -f docker/docker-compose.mode5.yml up -d rustfs rustfs-init
docker compose -f docker/docker-compose.mode5.yml up mode5-root-broker-fs-init mode5-issuer-fs-init mode5-db-bootstrap
docker compose -f docker/docker-compose.mode5.yml up -d mode5-root-broker mode5-field-key-issuer tr-mode5-field-recipient-registrar
# 3. sign-in services and the web
docker compose -f docker/docker-compose.mode5.yml up -d account-oidc-binding-verifier account-ed25519-login-verifier web
docker compose -f docker/docker-compose.mode5.yml logs -f web

What is now running:

  • web — the SSR web application, API and sync relay (community build)
  • postgres — PostgreSQL 16 with pgsodium
  • mode5-root-broker, field-key-issuer, recipient-registrar — the end-to-end encryption root and field keys; the broker has no network
  • general-biscuit-signer, account-* — session signing and sign-in services
  • rustfs — S3-compatible object storage
  • rauthy, caddy — OIDC provider and TLS reverse proxy
Export the encryption root key to offline storage during the ceremony step of the runbook. If the host is lost without that export, every end-to-end encrypted project on the node is unrecoverable.

SSL Certificates

Caddy issues and renews the certificate automatically once DNS points at the host:

bash
# Caddyfile
node.example.org {
reverse_proxy web:3000
}
auth.node.example.org {
reverse_proxy rauthy:8080
}
WebSocket sync on /crdt/ws works through Caddy without extra configuration; with nginx you must forward the Upgrade and Connection headers.

Step 4: Setup Authentication

Thumper-Run uses Rauthy for OpenID Connect (OIDC) authentication. After the first boot, you need to create an admin account and configure the OIDC client.

Create your account in Rauthy

  1. Open https://auth.node.example.org/auth/v1/admin and sign in with the bootstrap credentials Rauthy printed on first start; change that password now
  2. Create the user whose email you put in INITIAL_RELAY_ADMIN_EMAIL — that account becomes the node operator on first sign-in
  3. Optionally add upstream providers (Google, GitHub) under Providers

Register the OIDC client

bash
# Creates the client "Thumper Run" with the node's redirect URI
python3 scripts/rauthy-provision-client.py \
--rauthy-url https://auth.node.example.org \
--client-name "Thumper Run" \
--redirect-uri https://node.example.org/auth/callback
# Put the printed client id in RAUTHY_CLIENT_ID and the secret in ./secrets/, then restart web
The redirect URI registered in Rauthy and RAUTHY_REDIRECT_URI must both be TR_PUBLIC_URL followed by /auth/callback.

Step 5: Verify and Connect

Let’s verify your deployment is working and connect the desktop app.

Health Check

bash
# Check the web server health endpoint
curl -fsS https://node.example.org/readyz
curl -fsS https://node.example.org/version | python3 -m json.tool # edition, api_version, source_url
curl -fsS https://node.example.org/api/v1/client-config | python3 -m json.tool | grep -A3 '"node"'
# Expected: {"status": "ok", "version": "..."}

Connect Desktop App

  1. Open the Thumper-Run desktop app on your local machine
  2. Go to Settings → Sync → Nodes → Add node (node switching on every platform is in progress; until it ships, use the node’s web app in a browser)
  3. Enter https://node.example.org, check the probe result (edition, version), then Set active
  4. Click "Connect" — you’ll be redirected to the Rauthy login page
  5. Sign in with your user credentials
  6. The sync indicator in the sidebar should turn green
Multiple desktop clients can connect to the same server. CRDT sync keeps everything consistent across devices.

Key Takeaways

  • Deployment uses Docker Compose with four services: web, rauthy, postgres, nginx
  • Rauthy provides OIDC authentication — run the provisioning script after first boot
  • All configuration lives in the .env file — never commit it to version control
  • Connect clients through Settings → Sync → Nodes
  • Set up SSL certificate auto-renewal with Let’s Encrypt and certbot

Next Steps