mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add production Docker Compose bundle (#985)
Signed-off-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr <5a968df9a7494b4e019b9ecf739e088ba61097b4312124e9a88ae5b42e3f5f3e@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
co-authored by
npub1t2tgm7d8f995uqvmnm8h88sg3wnpp9a5xysjf6dg3tjmgt3ltulqdp8ehr
npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta
parent
a32681fd48
commit
6caa359d70
@@ -0,0 +1,52 @@
|
||||
# Buzz production Docker Compose environment.
|
||||
# Copy to .env and replace every CHANGE_ME value before running.
|
||||
# The bootstrap script should generate this file for normal users.
|
||||
|
||||
# Image published by the public image pipeline. Use `:main` for pre-release testing. Pin `:sha-<7>` or a semver release tag for production.
|
||||
BUZZ_IMAGE=ghcr.io/block/buzz:main
|
||||
|
||||
# Public host name. Used by compose.caddy.yml and URL-derived settings below.
|
||||
BUZZ_DOMAIN=buzz.example.com
|
||||
RELAY_URL=wss://buzz.example.com
|
||||
BUZZ_MEDIA_BASE_URL=https://buzz.example.com/media
|
||||
BUZZ_MEDIA_SERVER_DOMAIN=buzz.example.com
|
||||
BUZZ_CORS_ORIGINS=https://buzz.example.com
|
||||
|
||||
# Production defaults. Closed relay mode requires RELAY_OWNER_PUBKEY and a stable relay key.
|
||||
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
|
||||
|
||||
# Owner identity. Set to a 64-character hex Nostr pubkey.
|
||||
RELAY_OWNER_PUBKEY=CHANGE_ME_OWNER_PUBKEY_HEX
|
||||
|
||||
# Stable secrets. Generate once, keep in .env, and back up securely.
|
||||
BUZZ_RELAY_PRIVATE_KEY=CHANGE_ME_64_HEX_PRIVATE_KEY
|
||||
BUZZ_GIT_HOOK_HMAC_SECRET=CHANGE_ME_RANDOM_64_HEX
|
||||
POSTGRES_DB=buzz
|
||||
POSTGRES_USER=buzz
|
||||
POSTGRES_PASSWORD=CHANGE_ME_RANDOM_PASSWORD
|
||||
REDIS_PASSWORD=CHANGE_ME_RANDOM_PASSWORD
|
||||
TYPESENSE_API_KEY=CHANGE_ME_RANDOM_API_KEY
|
||||
BUZZ_S3_ACCESS_KEY=CHANGE_ME_RANDOM_ACCESS_KEY
|
||||
BUZZ_S3_SECRET_KEY=CHANGE_ME_RANDOM_SECRET_KEY
|
||||
BUZZ_S3_BUCKET=buzz-media
|
||||
|
||||
# Optional host ports. Base compose publishes the relay directly on BUZZ_HTTP_PORT.
|
||||
BUZZ_HTTP_PORT=3000
|
||||
|
||||
# Caddy host ports. Only used with compose.caddy.yml.
|
||||
CADDY_HTTP_PORT=80
|
||||
CADDY_HTTPS_PORT=443
|
||||
|
||||
# Dev override ports. Only used with compose.dev.yml.
|
||||
POSTGRES_PORT=5432
|
||||
REDIS_PORT=6379
|
||||
TYPESENSE_PORT=8108
|
||||
MINIO_API_PORT=9000
|
||||
MINIO_CONSOLE_PORT=9001
|
||||
ADMINER_PORT=8082
|
||||
PROMETHEUS_PORT=9090
|
||||
@@ -0,0 +1,5 @@
|
||||
{$BUZZ_DOMAIN} {
|
||||
encode zstd gzip
|
||||
|
||||
reverse_proxy relay:3000
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Buzz Docker Compose deployment
|
||||
|
||||
This is the single-node/VPS deployment bundle. It is intentionally separate from
|
||||
the root `docker-compose.yml`, which remains local development infrastructure.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
cd deploy/compose
|
||||
cp .env.example .env
|
||||
$EDITOR .env # replace every CHANGE_ME value
|
||||
./run.sh start
|
||||
```
|
||||
|
||||
For a public VPS with automatic Let's Encrypt certificates:
|
||||
|
||||
```bash
|
||||
cd deploy/compose
|
||||
BUZZ_COMPOSE_TLS=true ./run.sh start
|
||||
```
|
||||
|
||||
The bootstrap script should eventually replace manual `.env` editing for normal
|
||||
users. It is responsible for generating stable secrets and, optionally, an owner
|
||||
keypair.
|
||||
|
||||
## Production notes
|
||||
|
||||
- Requires Docker Compose v2.24.4 or newer; the TLS override uses Compose's
|
||||
`!reset` tag to remove the direct relay port when Caddy terminates HTTPS.
|
||||
- Default `BUZZ_IMAGE` tracks `ghcr.io/block/buzz:main` for early testing. Pin it to `ghcr.io/block/buzz:sha-<7>` or a semver release tag for production once available.
|
||||
- Keep `BUZZ_RELAY_PRIVATE_KEY`, `BUZZ_GIT_HOOK_HMAC_SECRET`, database/Redis,
|
||||
Typesense, and S3 secrets stable across restarts.
|
||||
- `RELAY_OWNER_PUBKEY` is intentionally not prefixed with `BUZZ_`; it must be a
|
||||
64-character hex Nostr pubkey when closed relay mode is enabled.
|
||||
- `BUZZ_AUTO_MIGRATE=true` requires an image that includes embedded SQLx
|
||||
migrations. Do not share this quick start for a fresh public install until PR
|
||||
#988 is merged and `ghcr.io/block/buzz:main` has been rebuilt from it. Before
|
||||
then, this bundle is only suitable for instances whose database schema has
|
||||
already been applied.
|
||||
- The stack uses Postgres, Redis, Typesense, MinIO, and a git data volume because
|
||||
those are real Buzz dependencies today. Minimal mode can simplify this later.
|
||||
|
||||
Run `./run.sh backup-hint` for the backup checklist.
|
||||
|
||||
## Validation
|
||||
|
||||
Before sharing an install link publicly, verify a fresh install with:
|
||||
|
||||
```bash
|
||||
cd deploy/compose
|
||||
cp .env.example .env
|
||||
$EDITOR .env
|
||||
./run.sh config
|
||||
./run.sh start
|
||||
curl -fsS "http://127.0.0.1:$(grep -E '^BUZZ_HTTP_PORT=' .env | cut -d= -f2-)/_liveness"
|
||||
./run.sh status
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
services:
|
||||
relay:
|
||||
ports: !reset []
|
||||
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
depends_on:
|
||||
relay:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
BUZZ_DOMAIN: ${BUZZ_DOMAIN:?set BUZZ_DOMAIN}
|
||||
ports:
|
||||
- "${CADDY_HTTP_PORT:-80}:80"
|
||||
- "${CADDY_HTTPS_PORT:-443}:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
- buzz-caddy-data:/data
|
||||
- buzz-caddy-config:/config
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
volumes:
|
||||
buzz-caddy-data:
|
||||
labels:
|
||||
com.buzz.volume: caddy-data
|
||||
buzz-caddy-config:
|
||||
labels:
|
||||
com.buzz.volume: caddy-config
|
||||
@@ -0,0 +1,52 @@
|
||||
services:
|
||||
postgres:
|
||||
ports:
|
||||
- "${POSTGRES_PORT:-5432}:5432"
|
||||
|
||||
redis:
|
||||
ports:
|
||||
- "${REDIS_PORT:-6379}:6379"
|
||||
|
||||
typesense:
|
||||
environment:
|
||||
TYPESENSE_ENABLE_CORS: "true"
|
||||
ports:
|
||||
- "${TYPESENSE_PORT:-8108}:8108"
|
||||
|
||||
minio:
|
||||
ports:
|
||||
- "${MINIO_API_PORT:-9000}:9000"
|
||||
- "${MINIO_CONSOLE_PORT:-9001}:9001"
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
container_name: buzz-adminer
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
ADMINER_DEFAULT_SERVER: postgres
|
||||
ports:
|
||||
- "${ADMINER_PORT:-8082}:8080"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: buzz-prometheus
|
||||
volumes:
|
||||
- ../../prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- buzz-prometheus-data:/prometheus
|
||||
ports:
|
||||
- "${PROMETHEUS_PORT:-9090}:9090"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
volumes:
|
||||
buzz-prometheus-data:
|
||||
labels:
|
||||
com.buzz.volume: prometheus
|
||||
@@ -0,0 +1,168 @@
|
||||
name: buzz-prod
|
||||
|
||||
services:
|
||||
relay:
|
||||
image: ${BUZZ_IMAGE:-ghcr.io/block/buzz:main}
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
BUZZ_BIND_ADDR: 0.0.0.0:3000
|
||||
BUZZ_HEALTH_PORT: "8080"
|
||||
BUZZ_METRICS_PORT: "9102"
|
||||
DATABASE_URL: postgres://${POSTGRES_USER:-buzz}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-buzz}
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD:?set REDIS_PASSWORD}@redis:6379
|
||||
TYPESENSE_URL: http://typesense:8108
|
||||
BUZZ_S3_ENDPOINT: http://minio:9000
|
||||
BUZZ_S3_ACCESS_KEY: ${BUZZ_S3_ACCESS_KEY:?set BUZZ_S3_ACCESS_KEY}
|
||||
BUZZ_S3_SECRET_KEY: ${BUZZ_S3_SECRET_KEY:?set BUZZ_S3_SECRET_KEY}
|
||||
BUZZ_S3_BUCKET: ${BUZZ_S3_BUCKET:-buzz-media}
|
||||
BUZZ_GIT_REPO_PATH: /data/git
|
||||
BUZZ_AUTO_MIGRATE: ${BUZZ_AUTO_MIGRATE:-true}
|
||||
BUZZ_GIT_CONFORMANCE_PROBE: ${BUZZ_GIT_CONFORMANCE_PROBE:-true}
|
||||
ports:
|
||||
- "${BUZZ_HTTP_PORT:-3000}:3000"
|
||||
volumes:
|
||||
- buzz-git-data:/data/git
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
typesense:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
condition: service_healthy
|
||||
minio-init:
|
||||
condition: service_completed_successfully
|
||||
# Probe /_readiness over /dev/tcp because the runtime image has bash but no curl/wget/socat.
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"bash -ec 'exec 3<>/dev/tcp/127.0.0.1/8080; printf \"GET /_readiness HTTP/1.1\\r\\nHost: 127.0.0.1\\r\\nConnection: close\\r\\n\\r\\n\" >&3; grep -q \"200 OK\" <&3'",
|
||||
]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 12
|
||||
start_period: 30s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
postgres:
|
||||
image: postgres:18-alpine
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-buzz}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-buzz}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
volumes:
|
||||
- buzz-postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:?set REDIS_PASSWORD}"]
|
||||
environment:
|
||||
REDIS_PASSWORD: ${REDIS_PASSWORD:?set REDIS_PASSWORD}
|
||||
volumes:
|
||||
- buzz-redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli -a \"$${REDIS_PASSWORD}\" ping | grep -q PONG"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 12
|
||||
start_period: 5s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
typesense:
|
||||
image: typesense/typesense:30.2
|
||||
environment:
|
||||
TYPESENSE_DATA_DIR: /data
|
||||
TYPESENSE_API_KEY: ${TYPESENSE_API_KEY:?set TYPESENSE_API_KEY}
|
||||
TYPESENSE_ENABLE_CORS: "false"
|
||||
volumes:
|
||||
- buzz-typesense-data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"bash -c 'exec 3<>/dev/tcp/127.0.0.1/8108; printf \"GET /health HTTP/1.1\\r\\nHost: 127.0.0.1\\r\\nConnection: close\\r\\n\\r\\n\" >&3; cat <&3 | grep -q ok'",
|
||||
]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${BUZZ_S3_ACCESS_KEY:?set BUZZ_S3_ACCESS_KEY}
|
||||
MINIO_ROOT_PASSWORD: ${BUZZ_S3_SECRET_KEY:?set BUZZ_S3_SECRET_KEY}
|
||||
volumes:
|
||||
- buzz-minio-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
minio-init:
|
||||
image: minio/mc:RELEASE.2025-08-13T08-35-41Z
|
||||
depends_on:
|
||||
minio:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
BUZZ_S3_ACCESS_KEY: ${BUZZ_S3_ACCESS_KEY:?set BUZZ_S3_ACCESS_KEY}
|
||||
BUZZ_S3_SECRET_KEY: ${BUZZ_S3_SECRET_KEY:?set BUZZ_S3_SECRET_KEY}
|
||||
BUZZ_S3_BUCKET: ${BUZZ_S3_BUCKET:-buzz-media}
|
||||
entrypoint: >
|
||||
/bin/sh -euc '
|
||||
mc alias set local http://minio:9000 "$${BUZZ_S3_ACCESS_KEY}" "$${BUZZ_S3_SECRET_KEY}"
|
||||
mc mb --ignore-existing "local/$${BUZZ_S3_BUCKET}"
|
||||
mc anonymous set none "local/$${BUZZ_S3_BUCKET}"
|
||||
'
|
||||
restart: "no"
|
||||
networks:
|
||||
- buzz-net
|
||||
|
||||
volumes:
|
||||
buzz-postgres-data:
|
||||
labels:
|
||||
com.buzz.volume: postgres
|
||||
buzz-redis-data:
|
||||
labels:
|
||||
com.buzz.volume: redis
|
||||
buzz-typesense-data:
|
||||
labels:
|
||||
com.buzz.volume: typesense
|
||||
buzz-minio-data:
|
||||
labels:
|
||||
com.buzz.volume: minio
|
||||
buzz-git-data:
|
||||
labels:
|
||||
com.buzz.volume: git
|
||||
|
||||
networks:
|
||||
buzz-net:
|
||||
driver: bridge
|
||||
labels:
|
||||
com.buzz.network: production
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "${SCRIPT_DIR}"
|
||||
|
||||
COMPOSE_FILES=(-f compose.yml)
|
||||
if [[ "${BUZZ_COMPOSE_TLS:-false}" == "true" ]]; then
|
||||
COMPOSE_FILES+=(-f compose.caddy.yml)
|
||||
fi
|
||||
if [[ "${BUZZ_COMPOSE_DEV:-false}" == "true" ]]; then
|
||||
COMPOSE_FILES+=(-f compose.dev.yml)
|
||||
fi
|
||||
|
||||
compose() {
|
||||
docker compose --env-file .env "${COMPOSE_FILES[@]}" "$@"
|
||||
}
|
||||
|
||||
require_env() {
|
||||
if [[ ! -f .env ]]; then
|
||||
cat >&2 <<'MSG'
|
||||
Missing deploy/compose/.env.
|
||||
|
||||
Copy .env.example to .env and replace every CHANGE_ME value, or run the bootstrap
|
||||
script once it lands. Do not start production with generated secrets missing.
|
||||
MSG
|
||||
exit 1
|
||||
fi
|
||||
if grep -Eq '^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*=.*CHANGE_ME' .env; then
|
||||
cat >&2 <<'MSG'
|
||||
deploy/compose/.env still contains CHANGE_ME placeholders.
|
||||
Generate stable secrets first; these values must not rotate on restart.
|
||||
MSG
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
backup_hint() {
|
||||
cat <<'MSG'
|
||||
Back up these before upgrades and on a regular schedule:
|
||||
|
||||
- deploy/compose/.env, especially BUZZ_RELAY_PRIVATE_KEY, DB/Redis/Typesense/S3 secrets, and BUZZ_GIT_HOOK_HMAC_SECRET
|
||||
- The owner private key if bootstrap generated one for RELAY_OWNER_PUBKEY
|
||||
- Postgres data (prefer pg_dump or a quiesced volume snapshot)
|
||||
- MinIO/S3 bucket contents for media and git objects
|
||||
- buzz-git-data volume (BUZZ_GIT_REPO_PATH=/data/git)
|
||||
- Caddy data/config volumes if using compose.caddy.yml
|
||||
|
||||
Keep Postgres + object/git state snapshots from the same maintenance window.
|
||||
MSG
|
||||
}
|
||||
|
||||
case "${1:-help}" in
|
||||
start|up)
|
||||
require_env
|
||||
compose up -d --wait
|
||||
;;
|
||||
stop|down)
|
||||
compose down
|
||||
;;
|
||||
restart)
|
||||
require_env
|
||||
compose up -d --wait --force-recreate relay
|
||||
;;
|
||||
pull)
|
||||
require_env
|
||||
compose pull
|
||||
;;
|
||||
upgrade)
|
||||
require_env
|
||||
compose pull
|
||||
compose up -d --wait
|
||||
backup_hint
|
||||
;;
|
||||
logs)
|
||||
shift || true
|
||||
compose logs -f "${@:-relay}"
|
||||
;;
|
||||
status|ps)
|
||||
compose ps
|
||||
;;
|
||||
config)
|
||||
require_env
|
||||
compose config
|
||||
;;
|
||||
backup-hint)
|
||||
backup_hint
|
||||
;;
|
||||
help|-h|--help)
|
||||
cat <<'MSG'
|
||||
Usage: ./run.sh <command>
|
||||
|
||||
Commands:
|
||||
start Start Buzz with docker compose up -d --wait
|
||||
stop Stop containers without deleting volumes
|
||||
restart Recreate the relay after env/image changes
|
||||
pull Pull configured images
|
||||
upgrade Pull and restart, then print backup reminders
|
||||
logs [svc] Follow logs (default: relay)
|
||||
status Show compose service status
|
||||
config Render merged compose config
|
||||
backup-hint Print the production backup checklist
|
||||
|
||||
Environment switches:
|
||||
BUZZ_COMPOSE_TLS=true Include compose.caddy.yml for automatic HTTPS
|
||||
BUZZ_COMPOSE_DEV=true Include compose.dev.yml for local admin ports/tools
|
||||
MSG
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $1" >&2
|
||||
echo "Run ./run.sh help" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user