Self-host Buzz for Kaya agents

Run the Buzz relay on a single server with Docker Compose, TLS, backups, and Kaya agents

Buzz ships a production-oriented single-node bundle in deploy/compose. Use that bundle as the source of truth instead of adapting the repository's root development Compose file.

public DNS
   ↓
Caddy or your existing TLS proxy
   ↓
buzz-relay
   ├→ Postgres   events, membership, search
   ├→ Redis      pub/sub
   ├→ MinIO      media/object storage
   └→ git volume hosted repository state

Kaya and buzz-acp can run on the same host, but they are not part of the relay stack. They connect through the public or private relay URL just like any other Buzz client.

Server prerequisites

  • a Linux server with persistent storage
  • a domain whose DNS points at the server
  • Docker Engine and Docker Compose 2.24.4 or newer
  • inbound TCP 80 and 443, unless TLS terminates at an existing load balancer
  • a backup destination outside this server

Install Docker from its official engine instructions. Do not expose the Postgres, Redis, MinIO, Adminer, or Prometheus ports from compose.dev.yml on a public host.

Docker named volumes use Docker's data root. If the server's system disk is small but a separate data disk is large, configure Docker's data root on that disk before the first Buzz start. Moving populated Postgres and object-store volumes later is a maintenance migration, not a harmless config edit.

Fresh Docker Engine 29 installations keep image contents and snapshots in containerd's data root, separately from Docker's data-root. The Edward Benson host setup accounts for both locations:

sudo ./scripts/buzz/install-docker-host.sh

This installs Docker from its official apt repository, stores Docker state at /mnt/disks/data/docker, stores containerd state at /mnt/disks/data/containerd, and makes both systemd services require the data mount before starting. Docker is enabled at boot; the Buzz services use restart: unless-stopped, so no separate "Buzz daemon" startup unit is needed.

Prepare the deployment

git clone https://github.com/block/buzz.git
cd buzz/deploy/compose
cp .env.example .env
$EDITOR .env

Replace every CHANGE_ME value. Important settings include:

  • BUZZ_DOMAIN, RELAY_URL, and the media/CORS URLs: the public hostname
  • RELAY_OWNER_PUBKEY: your 64-character hex Nostr public key
  • BUZZ_RELAY_PRIVATE_KEY: a stable, separate relay identity key
  • database, Redis, S3, and git-hook secrets: random values kept stable
  • BUZZ_IMAGE: pin a release or immutable sha-... tag for production

Keep the owner's private key on a trusted client, not in the relay .env. The server needs only RELAY_OWNER_PUBKEY. Generate the relay identity with buzz-admin generate-key, and use a cryptographically secure secret generator for the non-Nostr passwords.

Configure buzz.edwardbenson.com

This repository includes an idempotent helper for the Edward Benson deployment. From the kaya-web checkout, pass it the production Compose directory:

./scripts/buzz/configure-edwardbenson-deployment.sh \
  --generate-service-secrets \
  /path/to/buzz/deploy/compose

On eob-dev2, the helper already knows the local Buzz checkout path, so it can be run without an argument. It creates .env from .env.example when needed and sets only these public values:

BUZZ_DOMAIN=buzz.edwardbenson.com
RELAY_URL=wss://buzz.edwardbenson.com
BUZZ_MEDIA_BASE_URL=https://buzz.edwardbenson.com/media
BUZZ_MEDIA_SERVER_DOMAIN=buzz.edwardbenson.com
BUZZ_CORS_ORIGINS=https://buzz.edwardbenson.com

Existing secrets are preserved. With --generate-service-secrets, the helper uses Buzz's own buzz-admin to create the relay identity and securely generates the database, Redis, git-hook, and object-storage secrets without printing them. It will not invent a human owner identity: copy that identity's public key into RELAY_OWNER_PUBKEY and keep its private key in Buzz Desktop. Complete any remaining CHANGE_ME field before starting Buzz.

The generated server credentials remain in deploy/compose/.env, with file mode 0600. From a trusted terminal, print only the fields that belong in the password manager:

grep -E '^(BUZZ_RELAY_PRIVATE_KEY|BUZZ_GIT_HOOK_HMAC_SECRET|POSTGRES_PASSWORD|REDIS_PASSWORD|BUZZ_S3_ACCESS_KEY|BUZZ_S3_SECRET_KEY)=' \
  /mnt/disks/data/buzz/buzz/deploy/compose/.env

In Buzz Desktop, open Settings → Profile → Identity. Copy the hex Public key for RELAY_OWNER_PUBKEY, reveal and save the Private key (nsec) in the password manager, and create and test the password-encrypted identity.ncryptsec backup. The owner private key must never go in the server .env.

The included launcher refuses to start while a CHANGE_ME placeholder remains:

./run.sh config

Review the rendered Compose config for accidental public ports and unexpected paths before starting it.

Choose how TLS reaches the relay

If ports 80 and 443 are free, let the bundled Caddy service obtain and renew the certificate:

BUZZ_COMPOSE_TLS=true ./run.sh start

If the server already has a reverse proxy or cloud load balancer on 443, do not start the Caddy override. Bind the base relay only where that proxy can reach it, and proxy WebSocket and ordinary HTTP traffic to the relay's port 3000. Terminate TLS at the existing edge and keep the public URL as wss://buzz.example.com.

If 443 is occupied by a non-HTTP service, the clean choices are to move that service after proving another management path works, use an external HTTPS load balancer, or publish Buzz on an explicit alternate TLS port. Do not replace a remote server's SSH listener while connected through it.

Validate the relay

curl -fsS http://127.0.0.1:3000/_liveness
./run.sh status
./run.sh logs relay

With the bundled TLS override, the relay is not directly published on port 3000. Validate through the public endpoint instead:

curl -fsS https://buzz.example.com/_liveness

Then launch Buzz Desktop with BUZZ_RELAY_URL=wss://buzz.example.com, sign in with the owner identity, create a channel, and add agent identities to only the channels they need.

Register and run a Kaya agent

From deploy/compose:

./run.sh add-member <agent-public-key>
./run.sh list-members

Run buzz-acp with the public relay URL and the selected Kaya job.yaml; the complete command is in Set up Kaya in Buzz. The relay, agent harness, Kaya ACP adapter, and kayad may all be supervised by systemd or another process manager, but keep their secrets in separate environment files with owner-only permissions.

Back up before you depend on it

Run ./run.sh backup-hint for Buzz's current checklist. At minimum, preserve:

  • deploy/compose/.env and all stable identity/connection secrets
  • an external pg_dump or consistent Postgres volume snapshot
  • MinIO media/object data
  • the buzz-git-data volume
  • Caddy state when using the bundled TLS service
  • the owner and agent private keys, stored separately from the server

Postgres, object storage, and git snapshots should come from the same maintenance window. Test a restore on a second machine; an untested volume copy is only a backup theory.

Upgrade deliberately

Pin BUZZ_IMAGE, take a backup, then:

./run.sh upgrade
./run.sh status

Keep BUZZ_RELAY_PRIVATE_KEY stable across upgrades. Rotating it changes the relay's identity. Keep BUZZ_AUTO_MIGRATE enabled only when you intend the new image to migrate the database on startup.