For self-hosters

Run it yourself.

Running the server yourself is the normal way to use Gryt. This page is the shortest way from wherever you are now to a server that works.

Getting one up

Five ways in, sorted by how much you have to know, not by which is best. Pick the first one you can already do. The first needs nothing but the app you downloaded. The last one is a Helm chart.

  1. Nothing you have not already got

    From the app

    The app you downloaded is a server too. Add Server, then Host a server, name it, and read the address out to whoever is joining. Anyone on the same network won't even need that.

    Guide
  2. A terminal, on Linux or macOS

    The gryt CLI

    One script installs a binary. Run gryt and press n. It asks eight questions with sensible defaults, writes the Compose files, picks ports nothing else is using, and starts a shared voice server and object store the first time. It needs Docker to run what it writes, so get that first.

    bash
    curl -fsSL https://get.gryt.chat | sh
    Guide
  3. Windows, and Node.js 22.13

    Windows

    A zip, one config file and start.bat. Node.js is the only thing you install yourself, and it has to be 22.13 or newer. The server uses the SQLite built into Node instead of a separate module, and 22.12 doesn’t have it.

    Guide
  4. Docker, and somewhere to put it

    Docker Compose

    A compose file and an .env, both grabbed with curl. No clone needed. Set the address people will reach you on, bring it up, and you have what most people running this for a community end up with.

    bash
    docker compose up -d
    Guide
  5. A Kubernetes cluster

    Helm chart

    ops/helm/gryt in the monorepo, with a README and example values. There’s no published chart repo and no docs page yet, so this one links to the chart itself.

    bash
    helm install my-gryt ./ops/helm/gryt
    The chart

What you are running

Four things. A Node server for accounts, channels, messages and uploads. A voice server written in Go that moves the audio and video around. Somewhere to put files, which is any S3-compatible storage. And a small worker that resizes images. On one machine that’s one docker compose up. The desktop app already has the first three inside it, which is why hosting from the app needs no terminal.

HTTPS · WebSocketput a proxy on itUDP 3478straight throughone machine, one docker compose upServerNode. Accounts, channels,messages, uploads.StorageAny S3-compatible bucket.MinIO in the compose file.Voice serverGo. Routes audio and videobetween people in a call.Image workerResizes what people upload:avatars, emoji, thumbnails.

Voice is WebRTC over UDP, and it's the one part a reverse proxy or a tunnel can't carry for you. One port, not a range. 3478 unless you change it, and it has to be reachable directly.

Reaching it from outside

Skip all of this if the server is only for people on your own network. Gryt servers announce themselves over mDNS, so on a LAN nobody types an address.

Going public is four lines in .env. Getting them wrong is the usual reason voice works on the LAN and for nobody else. The UDP port has to be open as UDP. A reverse proxy in front of the server doesn’t cover it.

.env
SFU_PUBLIC_HOST=wss://sfu.example.com
ICE_ADVERTISE_IP=203.0.113.10
ICE_UDP_MUX_PORT=3478
CORS_ORIGIN=http://127.0.0.1:15738,https://app.gryt.chat

The server doesn’t do TLS. It speaks plain HTTP and has no certificate of its own, so a domain means something in front of it. Caddy is the usual answer. It gets the certificates and renews them without being asked, and the config is two names pointed at two services.

Caddyfile
api.example.com {
    reverse_proxy server:5000
}

sfu.example.com {
    reverse_proxy sfu:5005
}

server and sfu are the compose service names, so it works from a Caddy container in the same file. The second name has to be the one in SFU_PUBLIC_HOST. And Caddy serves HTTP/3 on UDP 443 by default, which is one more reason not to put voice on 443.

Running it properly

The settings that start to matter once it is up and someone other than you is using it. Upgrading is the same two lines as installing, and pinning a version instead of following latest is what keeps it predictable.

bash
docker compose pull
docker compose up -d

Back up the server data directory first if you’re moving to a beta. A beta build can change the SQLite schema when it starts, and there’s no way back down. Going back means restoring that copy.

And read how to take one first. The database runs in WAL mode, so copying gryt.db on its own while the server is running can hand you an empty database, and nothing says so until the day you restore it.

Tools and when it breaks

What a server decides

Almost every limit in Gryt belongs to whoever runs the server, and there’s no tier above them that raises it. Uploads, avatars and emoji all start at 100 MB so nobody fills a disk by accident, and an owner can set any of them to whatever they want, including no limit at all. Voice starts at 96 kbps and goes to 510.

Two limits aren’t yours to set. Uploads go up in parts, so past your own limit the next one belongs to the storage. On S3 that’s 5 TB a file. And behind a Cloudflare Tunnel, the free plans cap uploads at 100 MB whatever your server says.

Why Gryt covers who you’re trusting, and with what. The deployment section of the docs has the full set of guides.