Self-hosting

Run your own OnlyTTY relay

One docker compose up brings up a relay on your domain, with automatic HTTPS. The relay is already end-to-end encrypted — it only ever forwards ciphertext — so you self-host for your own domain, your own limits, or a network you control, not for more privacy than the encryption already gives you.

Quick start

Clone the bundle, set two values, bring it up

The selfhost/ bundle is a Compose file and a Caddyfile. Caddy fetches and renews a Let's Encrypt certificate for your domain on its own — no certbot, no cron.

Get the bundle
$ git clone https://github.com/AndrewDryga/onlytty && cd onlytty/selfhost
Configure your domain + a secret
$ cp .env.example .env
Start — automatic HTTPS
$ docker compose up -d
Point your runner at it
$ onlytty --server https://relay.example.com

Why self-host

Reasons that hold up

Your own domain

Links read https://relay.example.com/s/… instead of onlytty.com — your brand, your URL, in every link and QR the runner prints.

Your own limits

Cap session lifetime, concurrency, frame size, and create-rate to your policy with a handful of environment variables.

A network you control

Keep the relay inside a VPC, behind a VPN, or air-gapped, so links only ever resolve where you want them to.

You serve the viewer

The browser viewer is code the relay host serves. Self-host and that code-delivery trust is yours, not a third party's.

What you run

One stateless container, behind TLS

The relay is a single Elixir container with no database — every session lives in memory, and nothing terminal-related is ever persisted, so there is nothing to back up. It needs exactly one thing in front of it: a TLS-terminating proxy. The bundle ships Caddy; bring your own nginx, Cloudflare, or Fly if you'd rather. The browser viewer uses the Web Crypto API, which only runs over HTTPS — so TLS isn't optional.

Outgrow one node and it clusters: every session is registered cluster-wide, so a runner and a viewer that land on different instances still pair. Keep your SECRET_KEY_BASE safe; everything else is reproducible from the image.

FAQ

Before you run it

Is it hard to run?
No. It's one container behind Caddy — docker compose up -d and Caddy fetches a TLS certificate for your domain on its own. There's no database to manage and nothing to back up.
Does self-hosting change the security model?
End-to-end encryption is identical — the relay only ever forwards ciphertext. What changes is code-delivery trust: the browser viewer is JavaScript your relay serves, so your browser trusts your relay at load time. Pin a release tag and check the published viewer hashes against it. The full model is in the security model.
Do I need a database or backups?
No. Sessions live in memory only; nothing terminal-related is persisted. Keep your SECRET_KEY_BASE and the deployment is fully reproducible from the image.
Can I run more than one node?
Yes. Every session is registered cluster-wide, so a runner and a viewer on different instances still pair. The production multi-node setup on GCP is in infra/.

From a fresh host to a working relay

The guide walks the whole path — the breeze setup, a bring-your-own-proxy config, the full configuration reference, and the security posture when you serve the viewer yourself.