declarative relay deployment on hetzner
relay-eval.waow.tech
atproto
relay
1# ATProto relay deployments
2
3> **experimental** — this is a personal project for learning ATProto infrastructure. the endpoints below may go down, lose data, or change without notice. do not depend on them for anything that matters.
4
5two full-network [ATProto](https://atproto.com) relays on independent Hetzner Cloud nodes with k3s:
6
7| | indigo (Go) | zlay (Zig) |
8|---|---|---|
9| **firehose** | `wss://relay.waow.tech` | `wss://zlay.waow.tech` |
10| **jetstream** | `wss://jetstream.waow.tech/subscribe` ([sidecar](https://github.com/bluesky-social/jetstream)) | — |
11| **collectiondir** | [lightrail](https://tangled.org/microcosm.blue/lightrail) sidecar on same endpoint | built-in (inspired by lightrail) |
12| **health** | [`relay.waow.tech/xrpc/_health`](https://relay.waow.tech/xrpc/_health) | [`zlay.waow.tech/_health`](https://zlay.waow.tech/_health) |
13| **metrics** | [`relay-metrics.waow.tech`](https://relay-metrics.waow.tech) | [`zlay-metrics.waow.tech`](https://zlay-metrics.waow.tech) |
14| **source** | [bluesky-social/indigo](https://github.com/bluesky-social/indigo) | [zzstoatzz.io/zlay](https://tangled.org/zzstoatzz.io/zlay) |
15
16## try it
17
18both scripts are self-contained [uv scripts](https://docs.astral.sh/uv/guides/scripts/) — no virtualenv or install needed.
19
20### firehose
21
22consumes the raw CBOR firehose using the [atproto](https://github.com/MarshalX/atproto) python SDK.
23
24```bash
25# watch posts scroll by for 10 seconds
26./scripts/firehose
27
28# run longer, filter by collection
29./scripts/firehose --duration 30
30./scripts/firehose --collection app.bsky.feed.like
31./scripts/firehose --duration 0 # forever (ctrl-c to stop)
32
33# point at a different relay
34./scripts/firehose --relay-url wss://zlay.waow.tech
35./scripts/firehose --relay-url wss://bsky.network
36```
37
38### jetstream
39
40consumes the simplified JSON firehose via [jetstream](https://github.com/bluesky-social/jetstream) — no atproto SDK needed, just plain websockets.
41
42```bash
43# watch all events for 10 seconds
44./scripts/jetstream
45
46# filter to specific collections
47./scripts/jetstream --collection app.bsky.feed.post
48./scripts/jetstream --collection app.bsky.feed.like --collection app.bsky.graph.follow
49
50# run longer, or forever
51./scripts/jetstream --duration 30
52./scripts/jetstream --duration 0 # forever (ctrl-c to stop)
53
54# point at a different jetstream instance
55./scripts/jetstream --url wss://jetstream1.us-east.bsky.network
56```
57
58## relay-eval
59
60[**relay-eval.waow.tech**](https://relay-eval.waow.tech) — compares what each atproto relay sees by subscribing to multiple firehoses simultaneously and measuring DID coverage overlap. inspired by [pulsar](https://tangled.sh/@mackuba.eu/pulsar) by mackuba (zlib license).
61
62source: [`relay-eval/`](relay-eval/)
63
64## what's here
65
66```
67.
68├── indigo/ # Go relay (indigo) — justfile, deploy configs, terraform
69├── zlay/ # zig relay (zlay) — justfile, deploy configs, terraform
70├── relay-eval/ # firehose comparison tool — zig, hetzner, systemd
71├── shared/deploy/ # helm values shared by both deployments
72├── scripts/ # uv scripts — firehose, jetstream, backfill
73├── docs/ # architecture, deployment guide, backfill
74└── justfile # root — `just indigo <recipe>` / `just zlay <recipe>`
75```
76
77each relay is a `just` module with symmetric recipes:
78
79```bash
80just indigo deploy # deploy Go relay
81just indigo status # check Go relay pods
82just zlay deploy # deploy zig relay
83just zlay status # check zig relay pods
84just --list # see all available recipes
85```
86
87## why
88
89the ATProto relay is the piece of infrastructure that aggregates writes from every PDS on the network into a single firehose stream. downstream services (appviews, feed generators, labelers) subscribe to a relay instead of crawling thousands of individual servers.
90
91running one is [surprisingly cheap](https://whtwnd.com/bnewbold.net/3lo7a2a4qxg2l) — the relay binary uses modest CPU and memory, and storage requirements are manageable. the main cost driver is bandwidth, which is why Hetzner (unlimited 1 Gbps) is a good fit.
92
93this repo is a template for deploying your own. everything is declarative: terraform for the VM, helm for the workloads, a justfile to tie it together. see [docs/deploying.md](docs/deploying.md) for setup instructions and [docs/architecture.md](docs/architecture.md) for how the pieces fit together.
94
95## prior art
96
97- [a full-network relay for $34 a month](https://whtwnd.com/bnewbold.net/3lo7a2a4qxg2l) by bryan newbold — the definitive guide
98- [atproto relay any% speedrun](https://pdsls.dev/at://did:plc:uu5axsmbm2or2dngy4gwchec/com.whtwnd.blog.entry/3lkubavdilf2m) — proof it runs on a raspberry pi
99- [running a PDS in kubernetes](https://hayden.leaflet.pub/3m4vfjkr6gc2p) — the app-template helm pattern
100- [firehose.network](https://sri.leaflet.pub/3mddrqk5ays27) — 3 public relays deployed globally