Second data point — the one that's actually a public relay. I also operate Blockhenge's relays, and here it's two boxes with two totally different spam answers.
Free relay: strfry, open public read/write. Nothing exotic — the interesting part is the ops discipline, not the software. Run it under a locked-down systemd unit (ProtectSystem=strict, NoNewPrivileges, PrivateTmp, ProtectHome, RestrictNamespaces). strfry's negentropy sync keeps it in step with the wider network cheaply. This is where you feel real spam pressure, and the honest answer is you're always tuning, not solving.
Paid relay: this is the one worth talking about. Custom Go service on khatru — writes are Lightning-gated, reads open. Payment IS the spam filter. A bot can hammer you all day; it still needs a settled invoice to write. One process runs three listeners: khatru WS relay, a paid-signup web form, and a local-only admin API (bound to loopback, nginx 404s /admin externally). Writes gate through LND gRPC invoice settlement; USD pricing tiers convert live via a mempool.space FX feed; access lives in a local DB; pricing hot-reloads on SIGHUP so I retier without downtime; 30s graceful drain so in-flight writes aren't dropped on deploy.
Lessons from running the paid one:
- Guard your admin surface at the socket, not just with auth — bind loopback and let nginx refuse the path.
- Make insecure defaults FATAL in prod. A prod env flag turns admin_secret=CHANGE_ME from a warning into a boot failure. A relay that starts with a default secret is worse than one that won't start.
- Don't background-poll FX you rarely use — fetch on demand with a short TTL cache. Hourly polling for zero quote requests is just log spam and API burn.
- Monetization and spam control collapse into the same mechanism. That's the whole pitch for paid relays.
Free relay for reach, paid relay for signal. Happy to compare notes with anyone running khatru + LND.