Deploy With Docker Compose
Deploy Buzz with the Docker Compose file on this page. It runs the published Buzz server image and Traefik on the same host. Buzz obtains the wildcard certificate itself through the Cloudflare API and publishes it to Traefik.
A deployment directory holds three files:
| File | Owner | Purpose |
|---|---|---|
docker-compose.yml |
Buzz release | Replaced on every update. Never edit it. |
.env |
Operator | Every Buzz setting. The server reads the whole file. |
compose.override.yml |
Operator | Optional local changes such as ports, labels, or Traefik settings. |
Before You Start
Section titled “Before You Start”Complete these prerequisites:
- Install Docker Engine with the Docker Compose plugin, version 2.24.4 or later.
- Host the DNS zone of
buzz.example.comon Cloudflare and pointbuzz.example.comand*.buzz.example.comat the host. - Allow inbound TCP traffic on ports
80and443. - Create a Cloudflare API token and a GitHub OAuth app.
- Complete the access decision in the Self-Hosting Overview. Configure upstream controls before deployment if Buzz is for a closed group.
Follow Configure DNS And TLS and Configure GitHub Authentication for the required credentials.
Configure The Deployment
Section titled “Configure The Deployment”-
Create a directory for the deployment and download the Compose file for Buzz 0.7.1:
Terminal window mkdir buzz && cd buzzcurl -fsSLo docker-compose.yml https://raw.githubusercontent.com/infomiho/buzzstatic/server-v0.7.1/server/docker-compose.ymlThe file pins the server release and the Traefik version it was tested with:
docker-compose.yml # Buzz standalone stack. Replace this file on every update and never edit it:# server settings live in .env, local changes in compose.override.yml.# Traefik reads its static configuration from the TRAEFIK_* variables below, so an# override can add or change single keys. Never give Traefik a command: any# command-line argument makes it ignore these variables.# Buzz obtains the certificate for BUZZ_DOMAIN and *.BUZZ_DOMAIN itself and# publishes it, with custom-domain routers, through the shared dynamic volume.services:traefik:image: traefik:v3.7.14restart: unless-stoppedenvironment:TRAEFIK_PROVIDERS_DOCKER: "true"TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: "false"TRAEFIK_PROVIDERS_FILE_DIRECTORY: /traefik/dynamicTRAEFIK_PROVIDERS_FILE_WATCH: "true"TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80"TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecureTRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME: httpsTRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: ":443"TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: /letsencrypt/acme-http.jsonTRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: webports:- "80:80"- "443:443"volumes:- /var/run/docker.sock:/var/run/docker.sock:ro- traefik-certs:/letsencrypt- traefik-dynamic:/traefik/dynamicserver:image: ghcr.io/infomiho/buzzstatic:0.7.1 # x-release-please-versionrestart: unless-stoppedenv_file: .envenvironment:BUZZ_DATA_DIR: /dataBUZZ_TRAEFIK_DYNAMIC_DIR: /traefik-dynamicBUZZ_TRAEFIK_HTTPS_ENTRYPOINT: websecureBUZZ_CUSTOM_DOMAIN_ORIGIN_HOST: traefikBUZZ_TRAEFIK_CERT_RESOLVER: letsencryptBUZZ_CLOUDFLARE_DNS_API_TOKEN: ${BUZZ_CLOUDFLARE_DNS_API_TOKEN:?Set BUZZ_CLOUDFLARE_DNS_API_TOKEN in .env}volumes:- buzz-data:/data- traefik-dynamic:/traefik-dynamiclabels:- traefik.enable=true- traefik.http.routers.buzz.rule=Host(`${BUZZ_DOMAIN:?Set BUZZ_DOMAIN in .env to the bare dashboard hostname, such as buzz.example.com}`)- traefik.http.routers.buzz.entrypoints=websecure- traefik.http.routers.buzz.tls=true- traefik.http.routers.buzz-wildcard.rule=HostRegexp(`.+\.${BUZZ_DOMAIN}`)- traefik.http.routers.buzz-wildcard.entrypoints=websecure- traefik.http.routers.buzz-wildcard.tls=true- traefik.http.services.buzz.loadbalancer.server.port=8080volumes:buzz-data:name: buzz_buzz-datatraefik-certs:name: buzz_traefik-certstraefik-dynamic:name: buzz_traefik-dynamic -
Create a
.envfile next to it:BUZZ_DOMAIN=buzz.example.comGITHUB_CLIENT_ID=your-github-client-idGITHUB_CLIENT_SECRET=your-github-client-secretBUZZ_CLOUDFLARE_DNS_API_TOKEN=your-cloudflare-api-tokenRestrict access with
chmod 600 .envand keep it out of source control. Add any other setting from the configuration reference to the same file. Every key in.envreaches the server, and an empty value counts as unset. Compose refuses to start whenBUZZ_DOMAINorBUZZ_CLOUDFLARE_DNS_API_TOKENis missing, and the server exits with anERROR:line naming any invalid value.
Start Buzz
Section titled “Start Buzz”Pull the pinned images and start the services:
docker compose up -dThe Compose project creates three named volumes:
buzz_buzz-datastores all Buzz data at/data, including the wildcard certificate in/data/tls.buzz_traefik-certsstores Traefik’s ACME state for custom domains inacme-http.json.buzz_traefik-dynamicholds the certificate and routers that Buzz publishes to Traefik. Buzz rewrites it from/data.
Do not remove buzz_buzz-data or buzz_traefik-certs during routine updates.
Verify The Deployment
Section titled “Verify The Deployment”-
Confirm that both containers are running and the server is healthy:
Terminal window docker compose ps -
Check the server through Traefik:
Terminal window curl --fail --show-error https://buzz.example.com/healthThe first certificate takes up to a few minutes after the first start. Until then Traefik serves its default certificate and
/healthreports"status":"degraded". The server logsWildcard certificate issued, valid untilonce it has published the certificate, and checks it through Traefik a few seconds later. Ifwildcard_certificate_errorstays set, the server logs name the cause. Buzz retries after 2, 5, 15, and 30 minutes, anddocker compose restart serverretries at once after you fix the cause. -
Open
https://buzz.example.comand start a GitHub sign-in.
If a container exits or TLS isn’t issued, inspect the logs:
docker compose logs server traefikSee Troubleshoot Self-Hosting for common causes.
Customize The Deployment
Section titled “Customize The Deployment”Put local changes in compose.override.yml. Compose loads it automatically and merges it into docker-compose.yml, so it survives every update. For example, to publish different host ports and raise Traefik’s log level:
services: traefik: environment: TRAEFIK_LOG_LEVEL: DEBUG ports: !override - "8080:80" - "8443:443"Traefik reads its static configuration from the TRAEFIK_* variables in docker-compose.yml. Add or change single keys under environment, as above. Do not set a command for Traefik: any command-line argument makes Traefik ignore all of these variables, so it opens no entrypoints and every site goes down.
Lists such as ports and labels are appended to by default. Use !override to replace a list.
Enable Custom Domains
Section titled “Enable Custom Domains”Custom domains are disabled by default. To let site owners add their own hostnames, add these values to .env:
BUZZ_CUSTOM_DOMAINS_ENABLED=trueBUZZ_CUSTOM_DOMAIN_INGRESS_IPS=203.0.113.10Set BUZZ_CUSTOM_DOMAIN_INGRESS_IPS to the host’s public IPv4 and IPv6 addresses, separated by commas. Recreate the services with docker compose up -d.
Buzz writes a router for each verified hostname into the shared buzz_traefik-dynamic volume. Traefik requests its certificate from Let’s Encrypt with the HTTP-01 challenge on port 80, through the letsencrypt resolver. The Compose file pins that resolver for the server, so a BUZZ_TRAEFIK_CERT_RESOLVER line in .env has no effect. Deploy With Coolify describes the site owner flow, Cloudflare proxy domains, and the operator endpoints, which work the same way here.
To disable custom domains, set BUZZ_CUSTOM_DOMAINS_ENABLED=false and run docker compose up -d. Buzz withdraws the remaining routers and logs All custom-domain routers are withdrawn.
Update Or Roll Back
Section titled “Update Or Roll Back”Create a cold backup before an update and read the release notes for the versions you skip past. Then replace the Compose file with the one from the new release and recreate the services. For Buzz 0.7.1:
curl -fsSLo docker-compose.yml https://raw.githubusercontent.com/infomiho/buzzstatic/server-v0.7.1/server/docker-compose.ymldocker compose pulldocker compose up -dFor another release, replace the version in the URL. Your .env and compose.override.yml stay untouched.
Confirm the new release is serving:
curl --fail --show-error https://buzz.example.com/versionDatabase migrations run automatically when the new server starts, and the instance is unavailable while they run. Before migrating, Buzz saves the database to /data/backups. Migrations are forward-only: an older image refuses to start against the migrated database and names the backup to restore. To roll back, stop the stack, download the previous release’s Compose file, restore the pre-migration backup or the cold backup, and start the stack again.
Choose An Image Tag
Section titled “Choose An Image Tag”The published image carries several tags:
| Tag | Meaning | Use |
|---|---|---|
<major>.<minor>.<patch> |
Exact release, immutable | Recommended. The Compose file pins this form. |
<major>.<minor> |
Latest patch release in the series | Unattended patch updates. |
latest |
Latest release | Not recommended. Deployments stop being reproducible. |
To run another tag, set image: for the server service in compose.override.yml. The pinned Compose file then no longer decides the server version, so remove the override before the next update.
For update notifications, watch releases on the GitHub repository or point Diun at the running containers. Avoid tools that auto-pull and restart running containers: an unattended update can run a database migration you did not plan for.
Upgrade From 0.6
Section titled “Upgrade From 0.6”This release moves wildcard issuance from Traefik into Buzz, configures Traefik through environment variables, and reads .env through env_file.
- Create a cold backup of both volumes, and copy
.env,docker-compose.yml, andcompose.override.ymlif it exists. - Move those edits into
compose.override.yml. Traefik settings becomeTRAEFIK_*keys underservices.traefik.environment, as in Customize The Deployment. Never give Traefik acommand. - Edit
.env:- Rename
CF_API_TOKENtoBUZZ_CLOUDFLARE_DNS_API_TOKEN. - Delete
ACME_EMAIL. - Delete
BUZZ_TRAEFIK_CONTROL_TOKEN,BUZZ_CUSTOM_DOMAIN_ACME_CA_SERVER,BUZZ_TRAEFIK_CERT_RESOLVER,BUZZ_CUSTOM_DOMAIN_ROUTING_ENABLED,BUZZ_CUSTOM_DOMAIN_ADMISSION_ENABLED,BUZZ_CLOUDFLARE_DIAGNOSTICS_ENABLED,BUZZ_CLOUDFLARE_ACTIVATION_ENABLED, andBUZZ_AUTOMATIC_DOMAIN_TRANSITION_ADMISSION_ENABLED. - Review the remaining keys. Every key now reaches the server, including keys the old Compose file ignored.
- Rename
- Download the new Compose file, pull, and restart, as in Update Or Roll Back.
Expect Traefik’s default certificate on every Buzz hostname until Buzz issues its wildcard, usually a few minutes. Activated custom hostnames answer 421 for up to about 90 seconds after the restart while Buzz checks them again, then get new production certificates from letsencrypt. The old acme.json in buzz_traefik-certs is no longer read. Delete it once you no longer need to roll back.
If you skip the upgrade, the old Compose file keeps working. Bumping only the image tag in the old file leaves the server container unhealthy, because the old healthcheck calls uv, which the image no longer ships, so replace the whole file. Leaving CF_API_TOKEN unrenamed makes Compose refuse to start.
To roll back, copy the saved docker-compose.yml, .env, and compose.override.yml back and run docker compose up -d --remove-orphans. The old Traefik serves its wildcard from acme.json again at once, and data written since the upgrade is kept.