Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions deploy/defang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Deploy Buzz to your own cloud with Defang

This bundle deploys a Buzz relay to **your** cloud account (AWS, GCP, Azure, or
DigitalOcean) using [Defang](https://defang.io) — a Docker-Compose-compatible
"bring your own cloud" deployment. It's the managed-services counterpart to the
single-node [`deploy/compose`](../compose/) bundle.

## Why a separate bundle

The VPS bundle runs Postgres, Redis, and MinIO as containers with persistent
volumes. Defang runs each service as a managed cloud primitive instead, which
means **no persistent volumes are required** — Buzz's durable git state is
object-store-backed, so the relay keeps no local state.

| Dependency | VPS (`deploy/compose`) | Defang (`deploy/defang`) |
|---|---|---|
| Database | `postgres` container + volume | managed Postgres (`x-defang-postgres`, e.g. RDS) |
| Cache/pubsub | `redis` container + volume | managed Redis (`x-defang-redis`, e.g. ElastiCache) |
| Object storage | `minio` + volume | your cloud's S3-compatible store (external S3) |
| TLS | Caddy | Defang load balancer + auto-cert |

## Prerequisites

- The [Defang CLI](https://docs.defang.io/docs/getting-started/installation) and
cloud credentials for your provider (e.g. `AWS_ACCESS_KEY_ID` /
`AWS_SECRET_ACCESS_KEY` for AWS).
- An S3-compatible bucket in your account for media + git objects, and
credentials scoped to it. (Defang doesn't yet provision object storage, so
create the bucket out-of-band.)

## Configure

Generate stable secrets and set every value with `defang config set`:

```bash
cd deploy/defang

# stable secrets (generate once, keep safe)
defang config set BUZZ_RELAY_PRIVATE_KEY # 64-char hex
defang config set BUZZ_GIT_HOOK_HMAC_SECRET # 32+ random chars
defang config set POSTGRES_PASSWORD # also used by managed Postgres
defang config set DATABASE_URL # postgres://buzz:<PASSWORD>@postgres:5432/buzz?sslmode=require

# owner identity (64-char hex Nostr pubkey)
defang config set RELAY_OWNER_PUBKEY

# object storage (AWS example)
defang config set BUZZ_S3_ENDPOINT # https://s3.<region>.amazonaws.com
defang config set BUZZ_S3_REGION # e.g. us-east-1
defang config set BUZZ_S3_BUCKET
defang config set BUZZ_S3_ACCESS_KEY
defang config set BUZZ_S3_SECRET_KEY

# public URL (set to your custom domain, or fill in after the first deploy with
# the Defang-assigned *.defang.app URL, then redeploy — do this before members join)
defang config set RELAY_URL # wss://<host>
defang config set BUZZ_DOMAIN # <host>
defang config set BUZZ_MEDIA_BASE_URL # https://<host>/media
defang config set BUZZ_MEDIA_SERVER_DOMAIN # <host>
defang config set BUZZ_CORS_ORIGINS # https://<host>
```

## Deploy

```bash
defang compose up
```

Defang provisions the managed database, cache, load balancer, and TLS cert, then
starts the relay. The first deploy prints the public URL. If you're using the
auto-assigned `*.defang.app` domain, set the `RELAY_URL`/`BUZZ_*` URL values to
it and redeploy once — before adding members, since the relay URL selects the
community.

## Notes

- The managed database/cache are reached over their compose **service names**
(`postgres`, `redis`); Defang wires those to the managed endpoints.
- Managed Redis is reached in-VPC without a password (`redis://redis:6379`).
- The load-balancer health check targets `/_liveness` on port 3000 (served by the
relay, no auth). The Buzz image ships no `curl`, so the healthcheck falls back
to a bash `/dev/tcp` probe for the in-container check.
- Back up `BUZZ_RELAY_PRIVATE_KEY`, your owner key, the database, and the object
store; the relay identity key is your community's identity.
132 changes: 132 additions & 0 deletions deploy/defang/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: buzz-relay

# Deploy a Buzz relay to your own cloud (AWS / GCP / Azure / DigitalOcean) with
# Defang (https://defang.io) — a Docker-Compose-compatible BYOC deployment that
# runs entirely in your cloud account.
#
# How this differs from deploy/compose (single-node / VPS):
# * postgres -> Defang managed database (x-defang-postgres; e.g. RDS on AWS)
# * redis -> Defang managed cache (x-defang-redis; e.g. ElastiCache)
# * minio -> your cloud's object store (real S3/GCS/etc. via Buzz's native
# external-S3 support)
# * no volumes: Buzz's durable git state is object-store-backed, so the relay
# keeps no persistent local state and needs no volumes.
# * caddy/TLS -> Defang's load balancer terminates TLS and gives the relay a
# public HTTPS/WSS URL automatically.
#
# One-time setup (values are stored encrypted, injected at runtime):
# defang config set RELAY_OWNER_PUBKEY BUZZ_RELAY_PRIVATE_KEY \
# BUZZ_GIT_HOOK_HMAC_SECRET POSTGRES_PASSWORD DATABASE_URL \
# BUZZ_S3_ENDPOINT BUZZ_S3_REGION BUZZ_S3_BUCKET \
# BUZZ_S3_ACCESS_KEY BUZZ_S3_SECRET_KEY \
# RELAY_URL BUZZ_DOMAIN BUZZ_MEDIA_BASE_URL BUZZ_MEDIA_SERVER_DOMAIN \
# BUZZ_CORS_ORIGINS
# then: defang compose up
#
# See deploy/defang/README.md for the full walkthrough.

services:
relay:
image: ${BUZZ_IMAGE:-ghcr.io/block/buzz:main}
restart: unless-stopped
ports:
- mode: ingress
target: 3000
published: 3000
environment:
BUZZ_BIND_ADDR: 0.0.0.0:3000
BUZZ_HEALTH_PORT: "8080"
BUZZ_METRICS_PORT: "9102"

# Closed community relay (owner + members).
BUZZ_REQUIRE_AUTH_TOKEN: "true"
BUZZ_REQUIRE_RELAY_MEMBERSHIP: "true"
BUZZ_ALLOW_NIP_OA_AUTH: "true"
BUZZ_AUTO_MIGRATE: "true"
BUZZ_GIT_CONFORMANCE_PROBE: "true"
RUST_LOG: "buzz_relay=info,buzz_db=info,buzz_auth=info,buzz_pubsub=info,tower_http=info"

# Managed cache (ElastiCache/etc.) — reachable in-VPC on the service name.
REDIS_URL: redis://redis:6379

BUZZ_S3_ADDRESSING_STYLE: virtual
BUZZ_GIT_REPO_PATH: /data/git

# ---- injected from `defang config` (blank = supplied at deploy time) ----
# Public URL / identity.
RELAY_URL:
BUZZ_DOMAIN:
BUZZ_MEDIA_BASE_URL:
BUZZ_MEDIA_SERVER_DOMAIN:
BUZZ_CORS_ORIGINS:
# Owner + stable relay secrets.
RELAY_OWNER_PUBKEY:
BUZZ_RELAY_PRIVATE_KEY:
BUZZ_GIT_HOOK_HMAC_SECRET:
# Managed database connection string (contains the DB password).
DATABASE_URL:
# Object storage (e.g. AWS S3: BUZZ_S3_ENDPOINT=https://s3.<region>.amazonaws.com).
BUZZ_S3_ENDPOINT:
BUZZ_S3_REGION:
BUZZ_S3_BUCKET:
BUZZ_S3_ACCESS_KEY:
BUZZ_S3_SECRET_KEY:
healthcheck:
# Defang configures the load-balancer health check from this URL. The relay
# serves /_liveness on the main port 3000 (no auth). The runtime image has
# no curl, so an equivalent bash /dev/tcp probe runs the in-container check.
test:
- CMD-SHELL
- "curl -fsS http://localhost:3000/_liveness || bash -c 'exec 3<>/dev/tcp/127.0.0.1/3000; printf \"GET /_liveness HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3; grep -q \"200 OK\" <&3'"
interval: 10s
timeout: 5s
retries: 12
start_period: 40s
deploy:
resources:
reservations:
cpus: "0.5"
memory: 1024M
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy

postgres:
image: postgres:17
x-defang-postgres: true
restart: unless-stopped
ports:
- mode: host
target: 5432
environment:
POSTGRES_USER: buzz
POSTGRES_DB: buzz
POSTGRES_PASSWORD:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U buzz -d buzz"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
deploy:
resources:
reservations:
cpus: "0.5"
memory: 1024M

redis:
# Defang derives the managed-cache engine version from the image tag; use
# <major>.<minor> (a bare "7" is rejected by ElastiCache).
image: redis:7.1
x-defang-redis: true
restart: unless-stopped
ports:
- mode: host
target: 6379
deploy:
resources:
reservations:
cpus: "0.25"
memory: 512M