feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled

Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
2026-08-13 18:34:25 +08:00
parent 61c3fa1df9
commit 9dfa06ffee
3785 changed files with 1085458 additions and 2 deletions
+57
View File
@@ -0,0 +1,57 @@
# 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
BUZZ_S3_ACCESS_KEY=CHANGE_ME_RANDOM_ACCESS_KEY
BUZZ_S3_SECRET_KEY=CHANGE_ME_RANDOM_SECRET_KEY
BUZZ_S3_BUCKET=buzz-media
# Bundled MinIO uses path-style URLs; deploy/compose/compose.yml pins this.
BUZZ_S3_ADDRESSING_STYLE=path
# Optional host ports. Base compose publishes the relay directly on BUZZ_HTTP_PORT.
BUZZ_HTTP_PORT=3000
# Optional custom Web UI. Setting this to an absolute directory containing
# index.html makes run.sh automatically include compose.web.yml. Leave unset to
# use the Web UI bundled in BUZZ_IMAGE.
# BUZZ_WEB_HOST_DIR=/opt/buzz/web/dist
# 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
MINIO_API_PORT=9000
MINIO_CONSOLE_PORT=9001
ADMINER_PORT=8082
PROMETHEUS_PORT=9090
+5
View File
@@ -0,0 +1,5 @@
{$BUZZ_DOMAIN} {
encode zstd gzip
reverse_proxy relay:3000
}
+61
View File
@@ -0,0 +1,61 @@
# 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,
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` is opt-in. Set `BUZZ_AUTO_MIGRATE=true` or run
`buzz-admin migrate` before starting the relay when bootstrapping a fresh
database. Auto-migration requires an image that includes embedded SQLx
migrations.
- The stack uses Postgres, Redis, MinIO, and a git data volume because
those are real Buzz dependencies today. Minimal mode can simplify this later.
- The bundled Compose stack fixes the relay endpoint to `http://minio:9000` and
`BUZZ_S3_ADDRESSING_STYLE=path`: Docker DNS resolves `minio`, not
`<bucket>.minio`. It is not configurable for an external S3 provider through
`.env`; use the Helm chart or a custom Compose configuration for providers
such as new Railway Storage Buckets that require `virtual` addressing.
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
```
+29
View File
@@ -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
+46
View File
@@ -0,0 +1,46 @@
services:
postgres:
ports:
- "${POSTGRES_PORT:-5432}:5432"
redis:
ports:
- "${REDIS_PORT:-6379}:6379"
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
+12
View File
@@ -0,0 +1,12 @@
services:
relay:
environment:
BUZZ_SERVE_GIT_WEB_GUI: "true"
BUZZ_WEB_DIR: /srv/buzz/web
volumes:
- type: bind
source: ${BUZZ_WEB_HOST_DIR:?set BUZZ_WEB_HOST_DIR to an absolute web dist directory}
target: /srv/buzz/web
read_only: true
bind:
create_host_path: false
+142
View File
@@ -0,0 +1,142 @@
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
BUZZ_S3_ENDPOINT: http://minio:9000
# Docker DNS resolves `minio`, not arbitrary `<bucket>.minio` hosts.
BUZZ_S3_ADDRESSING_STYLE: path
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:-false}
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
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:17-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:7-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
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-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
+191
View File
@@ -0,0 +1,191 @@
#!/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
WEB_OVERLAY_ENABLED=false
if [[ "${BUZZ_WEB_HOST_DIR+x}" == "x" ]] || {
[[ -f .env ]] && grep -Eq '^[[:space:]]*(export[[:space:]]+)?BUZZ_WEB_HOST_DIR[[:space:]]*=' .env
}; then
COMPOSE_FILES+=(-f compose.web.yml)
WEB_OVERLAY_ENABLED=true
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
}
read_web_host_dir() {
if [[ "${BUZZ_WEB_HOST_DIR+x}" == "x" ]]; then
printf '%s' "${BUZZ_WEB_HOST_DIR}"
return
fi
local value
value="$({
sed -nE 's/^[[:space:]]*(export[[:space:]]+)?BUZZ_WEB_HOST_DIR[[:space:]]*=[[:space:]]*(.*)$/\2/p' .env || true
} | tail -n 1)"
value="${value%$'\r'}"
value="${value#\"}"
value="${value%\"}"
value="${value#\'}"
value="${value%\'}"
printf '%s' "${value}"
}
validate_web_overlay() {
[[ "${WEB_OVERLAY_ENABLED}" == "true" ]] || return 0
local host_dir
host_dir="$(read_web_host_dir)"
if [[ -z "${host_dir}" ]]; then
echo "BUZZ_WEB_HOST_DIR is set but empty." >&2
exit 1
fi
if [[ "${host_dir}" != /* ]]; then
echo "BUZZ_WEB_HOST_DIR must be an absolute path." >&2
exit 1
fi
if [[ ! -d "${host_dir}" ]]; then
echo "BUZZ_WEB_HOST_DIR does not exist or is not a directory: ${host_dir}" >&2
exit 1
fi
if [[ ! -r "${host_dir}/index.html" ]]; then
echo "BUZZ_WEB_HOST_DIR must contain a readable index.html: ${host_dir}" >&2
exit 1
fi
}
validate_config() {
require_env
validate_web_overlay
# Quiet mode validates the merged model without printing resolved secrets.
compose config --quiet
}
backup_hint() {
cat <<'MSG'
Back up these before upgrades and on a regular schedule:
- deploy/compose/.env, especially BUZZ_RELAY_PRIVATE_KEY, DB/Redis/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)
validate_config
compose up -d --wait
;;
stop|down)
compose down
;;
restart)
validate_config
compose up -d --wait --force-recreate relay
;;
pull)
validate_config
compose pull
;;
upgrade)
validate_config
compose pull
compose up -d --wait
backup_hint
;;
logs)
shift || true
compose logs -f "${@:-relay}"
;;
status|ps)
compose ps
;;
config|validate)
validate_config
echo "Compose configuration is valid."
;;
backup-hint)
backup_hint
;;
add-member)
docker compose exec relay /usr/local/bin/buzz-admin add-member --pubkey "${2:?Usage: ./run.sh add-member <npub-or-hex> [--role member|admin]}" "${@:3}"
;;
remove-member)
docker compose exec relay /usr/local/bin/buzz-admin remove-member --pubkey "${2:?Usage: ./run.sh remove-member <npub-or-hex> [--role member|admin]}" "${@:3}"
;;
list-members)
docker compose exec relay /usr/local/bin/buzz-admin list-members
;;
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 Validate merged Compose config without printing secrets
validate Alias for config
backup-hint Print the production backup checklist
add-member <npub-or-hex> [--role member|admin]
Add a relay member (default role: member)
remove-member <npub-or-hex> [--role member|admin]
Remove a relay member
list-members List all relay members
Note: when adding multiple members in a loop, add `sleep 1` between
invocations to avoid same-second timestamp collisions in the kind:13534
roster event. Do not use parallel adds (e.g. xargs -P).
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
BUZZ_WEB_HOST_DIR=/abs Mount a custom web dist via compose.web.yml (read-only)
MSG
;;
*)
echo "Unknown command: $1" >&2
echo "Run ./run.sh help" >&2
exit 1
;;
esac