---
title: "Deploy Buzz | Open Source Slack Alternative with AI Agents"
description: "Self-hosted team chat with AI agents, git repos and QR pairing"
category: "AI/ML"
url: https://railway.com/deploy/buzz-relay-workspace
---

# Deploy Buzz | Open Source Slack Alternative with AI Agents

Self-hosted team chat with AI agents, git repos and QR pairing

**[Deploy Buzz | Open Source Slack Alternative with AI Agents on Railway](https://railway.com/template/buzz-relay-workspace)**

- **Creator:** katsuba.dev
- **Category:** AI/ML

## Template content

### Pairing https://cdn.jsdelivr.net/gh/block/buzz@6e5c462ac524de60d7edb46c66130fd779cc9006/desktop/src-tauri/icons/icon.png

- **Image:** ghcr.io/block/buzz:0.2.1
- **Start command:** `/usr/local/bin/buzz-pair-relay`
- **Public domain:** Yes

### Buzz https://cdn.jsdelivr.net/gh/block/buzz@6e5c462ac524de60d7edb46c66130fd779cc9006/desktop/src-tauri/icons/icon.png

- **Image:** ghcr.io/block/buzz:0.2.1
- **Start command:** `bash -c 'for i in $(seq 1 90); do (echo > /dev/tcp/$DB_WAIT_HOST/$DB_WAIT_PORT) 2>/dev/null && break; echo "waiting for postgres ($i/90)"; sleep 2; done; for i in $(seq 1 90); do (echo > /dev/tcp/$REDIS_WAIT_HOST/$REDIS_WAIT_PORT) 2>/dev/null && break; echo "waiting for redis ($i/90)"; sleep 2; done; o=$(printf %s "$RELAY_OWNER_PUBKEY" | tr "[:upper:]" "[:lower:]" | tr -d "[:space:]"); if [ -n "$o" ] && [ -z "${o##npub1*}" ]; then d=${o#npub1}; d=${d:0:${#d}-6}; cs=qpzry9x8gf2tvdw0s3jn54khce6mua7l; a=0; b=0; h=; for ((i=0;i<${#d};i++)); do c=${d:i:1}; t=${cs%%"$c"*}; if [ "$t" = "$cs" ]; then h=; break; fi; a=$(( (a<<5) | ${#t} )); b=$((b+5)); while [ $b -ge 8 ]; do b=$((b-8)); printf -v x "%02x" $(( (a>>b) & 255 )); h=$h$x; done; done; if [ ${#h} -eq 64 ]; then echo "RELAY_OWNER_PUBKEY: decoded npub to hex"; RELAY_OWNER_PUBKEY=$h; else echo "RELAY_OWNER_PUBKEY: starts with npub1 but did not decode - passing it through unchanged"; fi; else RELAY_OWNER_PUBKEY=$o; fi; export RELAY_OWNER_PUBKEY; exec /usr/local/bin/buzz-relay'`
- **Health check:** /_readiness
- **Public domain:** Yes

### Redis https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/redis.svg

- **Image:** redis:8.10.0-alpine

### Postgres https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/postgresql.svg

- **Image:** postgres:18.4-alpine

## Buckets

- **Bucket**

## Documentation

# Deploy and Host Buzz on Railway

Buzz is an open-source team communication platform from Block — channels, threads, huddles and git repositories, with AI agents as first-class members rather than bots bolted on. This template deploys the self-hosted relay with PostgreSQL, Redis, object storage and the device-pairing sidecar, fully wired.

## About Hosting Buzz

Four services and a bucket, all from official upstream images:

- **Buzz** — the relay: WebSocket protocol, REST API, git smart HTTP and the bundled web UI. Public domain, health check, and a signing identity generated on deploy.
- **Pairing** — the NIP-AB device-pairing sidecar, on its own domain. This is the piece that makes mobile QR pairing work; see below.
- **Postgres** — messages, channels, memberships and workspace state, on a volume.
- **Redis** — pub/sub between relay processes and rate-limit counters. Deliberately without a volume: nothing here is authoritative, and a Redis container cannot write to a Railway volume anyway — the way that fails is to stop accepting writes altogether.
- **Bucket** — Railway object storage, holding uploaded media **and every git repository**.

Every variable is filled in and described on the deploy screen. Exactly one is yours to supply — your Nostr public key, which is the account that owns the workspace.

Four things this template does that are worth knowing about:

**Mobile QR pairing actually works.** The relay advertises NIP-43 in its NIP-11 document, from which clients infer a `/pair` sidecar — and no self-hosted deployment stands one up. The Compose bundle has no such service and the Helm chart ships it disabled, so pairing a phone fails with `WebSocket connection failed: HTTP error: 404 Not Found` (upstream issue #3842). Upstream's workaround is a reverse proxy mapping `/pair`. Here the sidecar simply has a domain of its own and the relay advertises it directly, so nothing has to guess. Verified end to end: a signed `kind:24134` handshake published on one connection is delivered to a `#p`-filtered subscriber on another, and a tampered signature is rejected.

**It takes your key in the form you actually have it.** The relay accepts `RELAY_OWNER_PUBKEY` only as 64-character hex, and Nostr shows identities as `npub1…` — so pasting what is on your clipboard makes the relay log *"not a valid 64-char hex pubkey — ignoring"* and then refuse to boot, because membership enforcement needs an owner. A correct-looking value produces a crash loop. This template decodes bech32 in the start command and hands hex to the relay; either form works, and the log says which one it got.

**It waits for its databases.** The relay does not retry — it exits when Postgres or Redis is not answering yet, and Railway starts services in parallel, so on a cold deploy that race is the default rather than the exception. The start command waits for both first, and the relay is allowed enough restarts to survive a database restart later on.

**It pins a released version.** The image is `0.2.1`, the newest actual release and what `latest` resolves to. `main` is rebuilt on every merge into a repository that takes dozens of commits a day.

## Common Use Cases

- **A team chat you own**: channels, threads and huddles on your own domain, with the message history in your own database.
- **AI agents in the room**: agents join a workspace as members with their own identity, read the channels they are invited to, and answer in thread — the reason this is not simply another chat server.
- **Git hosting next to the conversation**: repositories are served over smart HTTP from the same relay that carries the discussion, so a review and the code live in one place.
- **A private workspace for a client or project**: one deployment per workspace, invited members only, and nothing shared with a vendor.

## Dependencies for Buzz Hosting

### Deployment Dependencies

- [Buzz](https://github.com/block/buzz) — the upstream project and its official image
- PostgreSQL for messages, channels and membership
- Redis for pub/sub and rate limiting
- An S3-compatible bucket for media and git objects

### Implementation Details

- **Your Nostr key is the whole account model.** `RELAY_OWNER_PUBKEY` is the identity that owns this workspace and the only one that can invite others. Create an identity in the Buzz desktop app first, copy the public key, and paste it on the deploy screen — `npub1…` or hex, both work. There is nothing to generate here: it is your identity, not the server's.
- **Repositories live in the bucket, not on a disk.** The relay keeps no authoritative per-repo filesystem state — refs are a manifest pointer updated by conditional write, packs are content-addressed objects. `BUZZ_GIT_REPO_PATH` is scratch space that repositories are hydrated into on demand, which is why the relay carries no volume. On every boot the relay runs upstream's conformance probe against the bucket and refuses to serve git if it fails, rather than finding out during someone's push.
- **The workspace is closed.** Members only, REST calls need a token, and a stranger who authenticates correctly is still turned away with `restricted: not a relay member`. Turning `BUZZ_REQUIRE_RELAY_MEMBERSHIP` off would make every message readable by anyone who finds the URL.
- **Do not repoint `RELAY_URL`.** The relay derives its workspace from the host in that URL, and an unrecognised host does not produce an error — it produces a brand-new empty workspace that looks exactly like one that lost all of its data (upstream issue #5378).
- **Two keys must stay stable.** `BUZZ_RELAY_PRIVATE_KEY` signs membership events and derives invite codes; rotating it invalidates every outstanding invite. `BUZZ_GIT_HOOK_HMAC_SECRET` signs git hook callbacks. Both are generated once on deploy.
- **The datastores are private.** No public TCP proxy on Postgres or Redis; they are reachable only from this project's private network.
- **Logging is turned down.** `tower_http` is at `warn`, because one line per request hits Railway's per-deployment log rate limit and drops the lines that matter. Raise it while debugging a client.

### Resource Usage and Cost

Measured on an idle deployment: **about 250 MB of RAM** across all four services — 203 MB of it Postgres, and 23 MB the relay itself — plus 2 GB of volume and whatever the bucket holds. That is roughly **$5–15/month** for a small team. Media, git objects and message volume drive it from there, mostly through storage.

## Why Deploy Buzz on Railway?

Buzz needs four moving parts wired to each other — a database, a cache, an object store that supports conditional writes, and a second listener for device pairing — before the first message is sent. Railway gives it a private network between them, managed object storage that passes the git conformance probe, a public domain with TLS for the WebSocket protocol, and a second domain for the pairing sidecar, which is the piece every other deployment path leaves out.

The alternative is a VM with a Compose file, where the certificates, the reverse-proxy rules for `/pair`, the bucket, the backups and the restart policy are all yours — and where the first thing you meet is a relay that exits because the database was not up yet.


## Similar templates

- [Chat Chat](https://railway.com/deploy/-WWW5r) — Chat Chat, your own unified chat and search to AI platform.
- [stella](https://railway.com/deploy/stella) — Self-host stella with web, API, Postgres, Redis, and object storage.
- [Hermes Agent | OpenClaw Alternative with Dashboard](https://railway.com/deploy/hermes-agent-or-openclaw-alternative-wit) — Self-Hosted Hermes AI Agent for Telegram, Discord & Slack

Open this page in a browser: https://railway.com/deploy/buzz-relay-workspace
