Skip to content

feat(server)!: own the wildcard certificate and route custom domains through Traefik's file provider - #36

Merged
infomiho merged 2 commits into
mainfrom
hosting-hardening
Oct 14, 2026
Merged

infomiho merged 2 commits into
mainfrom
hosting-hardening

Conversation

@infomiho

Copy link
Copy Markdown
Owner

Buzz now obtains its own wildcard certificate and routes custom domains through Traefik's file provider, so the proxy needs no Buzz-specific configuration. On Coolify, Reset configuration to default is always safe.

What changes

  • Wildcard certificate: Buzz orders BUZZ_DOMAIN and *.BUZZ_DOMAIN over Cloudflare DNS-01 with certbot's acme library, keeps it in /data/tls, and writes it to buzz-certificate.yaml in the Traefik dynamic directory. A missing or changed file is rewritten within 5 minutes without a new order.
  • Custom domains: routers go to buzz-routes.yaml in the same directory, acknowledged through a revision router. Traefik's API, the control token, the buzz-admin entrypoint and the HTTP provider are no longer used.
  • Health: /health reports "status": "degraded" (still HTTP 200) when the certificate can't be obtained, saved, published or served, or when custom-domain routers exist but the dynamic directory is unset. In that last case Buzz keeps serving its own sites and answers 421 for custom hostnames instead of refusing to start.
  • Upgrades: database migrations take a backup first. Invalid settings stop the server with ERROR: Invalid <NAME>. Empty values count as unset.
  • Image: multi-stage build with the virtualenv on PATH, no uv, digest-pinned bases.
  • CI: offline image smoke test and a Compose boot test from the latest release to the new image. Renovate keeps the Dockerfile and Compose digests current.

Breaking changes for self-hosters

  • Replace the whole Compose file, not only the image tag. A 0.6 Compose file with only its tag bumped leaves the container unhealthy, because its healthcheck calls uv.
  • Add BUZZ_CLOUDFLARE_DNS_API_TOKEN (Zone:Read and DNS:Edit on the zone).
  • Coolify: after deploying, reset the proxy to default, delete the old wildcard under Servers > Proxy > TLS Certificates, restart the proxy and redeploy. Other applications must work with HTTP-01.
  • Docker Compose: rename CF_API_TOKEN to BUZZ_CLOUDFLARE_DNS_API_TOKEN and delete ACME_EMAIL. Local Traefik edits move to compose.override.yml as TRAEFIK_* keys.
  • Removed variables: BUZZ_TRAEFIK_CONTROL_TOKEN, BUZZ_TRAEFIK_API_URL, BUZZ_TRAEFIK_API_AUTHORIZATION, BUZZ_TRAEFIK_CONTROL_PORT, BUZZ_CUSTOM_DOMAIN_ACME_CA_SERVER, BUZZ_CUSTOM_DOMAIN_ROUTING_ENABLED, BUZZ_CUSTOM_DOMAIN_ADMISSION_ENABLED, BUZZ_CLOUDFLARE_DIAGNOSTICS_ENABLED, BUZZ_CLOUDFLARE_ACTIVATION_ENABLED, BUZZ_AUTOMATIC_DOMAIN_TRANSITION_ADMISSION_ENABLED.
  • BUZZ_TRAEFIK_CERT_RESOLVER now defaults to letsencrypt, which must be HTTP-01.
  • /health can return "status": "degraded" with HTTP 200. Monitors matching the exact body {"status":"ok"} must check the status field.

The upgrade steps are in the Coolify and Docker Compose self-hosting pages.

Testing

  • Server: 710 tests. CLI: 146 tests. Docs check and build, actionlint, shellcheck.
  • Compose boot test from ghcr.io/infomiho/buzzstatic:latest to the new image.
  • End-to-end on a Coolify v4.4.3 VM with Pebble and a fake Cloudflare API: first issuance, self-heal after deleting the file, degraded mode without the dynamic directory, the full upgrade from a prod-shaped 0.6 proxy (about 19 s of downtime, no wildcard TLS gap), proxy Reset and restarts, and rollback.
  • Real Let's Encrypt staging issuance for static.miho.dev with a zone-scoped Cloudflare token.

https://claude.ai/code/session_01LCd93wpNDDvqEJpWZuX4oQ

@infomiho
infomiho merged commit ae5a637 into main Oct 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant