declarative relay deployment on hetzner relay.waow.tech
atproto

deploying#

prerequisites#

setup#

create a .env file:

export HCLOUD_TOKEN="your-hetzner-api-token"
export RELAY_DOMAIN="relay.yourdomain.com"
export RELAY_ADMIN_PASSWORD="something-secure"
export POSTGRES_PASSWORD="something-else-secure"
export LETSENCRYPT_EMAIL="you@example.com"

then:

source .env

just indigo init       # terraform init
just indigo infra      # creates a CPX41 in Ashburn (~$30/mo) with k3s via cloud-init
just indigo kubeconfig # waits for k3s, pulls kubeconfig (~2 min)
just indigo deploy     # installs cert-manager, postgresql, relay, jetstream, monitoring

point a DNS A record at the server IP (just indigo server-ip) before running deploy, so the Let's Encrypt HTTP-01 challenge succeeds.

after deploy, seed the relay with the network's PDS hosts:

just indigo bootstrap  # pulls hosts from upstream + restarts relay so slurper picks them up

available commands#

just indigo status     # nodes, pods, health check
just indigo logs       # tail relay logs
just indigo health     # curl the public health endpoint
just indigo reconnect  # re-announce all known PDS hosts to the relay
just indigo backfill   # backfill collectiondir with full network data
just indigo firehose   # consume the firehose (passes args through)
just indigo jetstream  # consume the jetstream (passes args through)
just indigo ssh        # ssh into the server
just indigo destroy    # tear down everything

maintenance#

a k8s CronJob (indigo/deploy/reconnect-cronjob.yaml) runs every 4 hours to re-announce PDS hosts to the relay — see architecture for why this is needed. just indigo reconnect runs the same logic manually.

targeted deployments#

just indigo deploy deploys everything. for targeted updates:

  • just indigo deploy-monitoring — only the monitoring stack (prometheus, grafana, dashboards, ServiceMonitors). useful for dashboard changes or prometheus config tweaks without touching the relay.