fix: update self-hosted docs for the Traefik reverse proxy - #911
Conversation
`getting-started-enterprise.sh` deploys Traefik instead of Caddy, but the enterprise getting-started page still described the Caddy stack. The worst of it was the custom-TLS appendix, which edits a `Caddyfile` the installer no longer generates, so it could not be followed at all. - Rewrite the custom TLS certificate appendix for Traefik: supply the certificate through the file provider, then remove both the ACME resolver flags and the four router `certresolver` labels. Removing the labels alone is not enough, because the certificate already stored in `acme.json` continues to be served in preference to the supplied one. - Document renewal correctly. Traefik watches the dynamic configuration file rather than the certificate files it references, so replacing the certificates has no effect until that file is touched. No container restart is needed. - Correct the certificate issuance guidance on the enterprise page and in certificate troubleshooting. The generated stack uses the TLS-ALPN-01 challenge only, so TCP/443 is what must be reachable; port 80 serves the HTTP→HTTPS redirect and is never used for validation. The community installer sets the same flag, so this applies to both. - Drop the `Caddyfile` row from the generated-files table. The installer writes `.env`, `docker-compose.yml` and `config.yaml` only, and configures routing and TLS through Traefik labels and command flags. - Replace `caddy` with `traefik` in the stack components table, the log commands, and the cleanup instructions, and fix `selfhosted-guide` still calling the bundled proxy Caddy where the same page elsewhere says Traefik. - Add the consequences that were previously unstated: a peer that does not trust a private issuing CA fails to connect, `config.yaml`'s empty `server.tls` block is intentional, and dropping the `80:80` mapping costs the HTTP→HTTPS redirect.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 30 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe self-hosted documentation now uses Traefik instead of Caddy as the default reverse proxy. It updates setup, HTTPS validation, certificate troubleshooting, custom certificates, deployment commands, and legacy Caddy guidance. ChangesTraefik self-hosted documentation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/selfhosted/enterprise/getting-started.mdx`:
- Around line 297-324: Update the Traefik setup instructions to use a
bind-mounted ./traefik directory at /etc/traefik/dynamic instead of mounting
traefik-dynamic.yaml directly. Replace the file provider filename command with
--providers.file.directory=/etc/traefik/dynamic, and adjust the dynamic
configuration file location and volume example accordingly while preserving the
certificate mount.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b5f81a71-f816-4fb6-a92e-bfba14146703
📒 Files selected for processing (3)
src/pages/selfhosted/enterprise/getting-started.mdxsrc/pages/selfhosted/selfhosted-guide.mdxsrc/pages/selfhosted/troubleshooting/certificates.mdx
A bind-mounted single file is pinned to one inode, so any tool that replaces the file rather than editing it in place — most editors, `sed -i`, many configuration-management tools — leaves the container reading the old content indefinitely, with no error and no way to recover by touching the new file. Traefik's own documentation recommends `directory` over `filename` for this reason. Switch to `--providers.file.directory=/etc/traefik/dynamic` with `./traefik` bind-mounted, and move the dynamic configuration to `traefik/dynamic.yaml`. The renewal instruction is otherwise unchanged: the certificates are referenced rather than watched, so they are picked up by touching the dynamic configuration, without restarting any container. Also drop the `tls.certificates` list from the example. It is redundant next to `stores.default.defaultCertificate`, which already covers every connection including clients that send no SNI.
The appendix sits on a page that also documents `migrate-to-enterprise.sh`, and the two paths differ. A migrated deployment is built on the community `getting-started.sh` render, which already configures a file provider when the reverse proxy is enabled. `providers.file.filename` and `providers.file.directory` are mutually exclusive, so following these steps verbatim there would declare a conflicting second provider. Note that deployments which already have a file provider should extend its dynamic configuration instead, and adjust router names to match their own Compose file.
Replace the em dashes added by the previous commits with commas, colons and parentheses. House convention is to reach for an em dash deliberately or not at all, and the appendix had accumulated eleven of them. Also state when not to follow the appendix at all: the default Let's Encrypt path renews itself, and everything in the appendix makes renewal the operator's responsibility. Expand SNI on first use.
Running the appendix against a real migrated deployment (community install with the built-in Traefik, then migrate-to-enterprise.sh with Postgres and traffic flow) showed the previous note pointed at the wrong difference. The four router names are identical to the fresh install, so there is nothing to adjust there. What actually differs is which file holds each label. `netbird-dashboard`, `netbird-grpc` and `netbird-backend` are in `docker-compose.yml`, while `netbird-flow` is on the `flow-receiver` service in `docker-compose.override.yml`, so the deletions span two files. The `traefik` service and the ACME flags stay in `docker-compose.yml`. Also state why a deployment that already has a file provider must extend it rather than add a second one: `providers.file.directory` and `providers.file.filename` are mutually exclusive.
The appendix had grown to four stacked callouts, two of them before the reader reaches the first step. Cut it from 690 to 554 words and from four callouts to two, without dropping anything load-bearing. Move the migrate-path and existing-file-provider caveats out of a 106 word preamble block and into the two steps they actually affect. Drop a decorative sentence about all routes passing through Traefik, shorten the inode note, and trim the SNI gloss to expanding the acronym.
The appendix is the supported way to serve a custom certificate, not a stopgap, so it should not hard-code "four labels, one on dashboard, two on netbird-server, one on receiver". That count goes stale the moment a router is added, and silently. Replace the enumeration with a grep over `docker-compose*.yml`. It is shorter, survives new routers, and spans `docker-compose.override.yml` on a migrated deployment, which removes the need for a separate note about where the `netbird-flow` label lives. Also reword the intro so the file provider reads as the mechanism you enable rather than something the installer failed to configure.
- The `traefik` directory was never created. "Create `traefik/dynamic.yaml`" fails in any editor that will not create a missing parent, so add the `mkdir -p traefik` the steps assumed. - `/certs` appeared in the dynamic configuration one step before the mount that defines it. Say that it is a container path and where it comes from. - Point the file-provider caveat at the named edit it refers to instead of "the next step's first edit", and reword the grep sentence.
Why
getting-started-enterprise.shdeploys Traefik instead of Caddy, but the enterprise getting-started page still describes the Caddy stack. The script served frompkgs.netbird.iohas no Caddy references at all, so operators following that page today already have Traefik in front of them.The worst of it is the custom TLS certificate appendix: every step edits a
Caddyfilethe installer no longer generates, so it cannot be followed.What changed
Custom TLS certificate appendix — rewritten for Traefik. The certificate is supplied through Traefik's file provider, which the generated stack does not enable, so this needs a new
traefik-dynamic.yamlplus edits todocker-compose.yml.The part worth reviewing closely: removing the four router
certresolverlabels is not sufficient. While the--certificatesresolvers.letsencrypt.acme.*flags remain, Traefik keeps loading the certificate already stored inacme.jsonand serves it for the deployment's own hostname in preference to the supplied one, so the stack looks like it is ignoring the operator's certificate. Both the flags and the labels have to go. Thenetbird_traefik_letsencryptvolume can stay as-is — with no resolver configured its contents are inert.Renewal. Traefik watches the dynamic configuration file, not the certificate files it references, so replacing the certificates alone has no effect. The appendix now says to
touch traefik-dynamic.yaml, which reloads the certificate without restarting any container. The previous Caddy instruction (docker compose restart caddy) has no Traefik equivalent.Certificate issuance guidance corrected, on the enterprise page and in
troubleshooting/certificates. Both claimed the ACME HTTP-01 challenge on port 80 matters. The generated stack setsacme.tlschallenge=trueand nothing else, so TCP/443 is what has to be reachable; port 80 only serves the HTTP→HTTPS redirect.getting-started.shsets the same flag, so the troubleshooting page was giving this advice to community deployments too — it now notes that pre-Traefik deployments still on Caddy are the exception.Stale references. Dropped the
Caddyfilerow from the generated-files table (the installer writes.env,docker-compose.ymlandconfig.yamlonly), swappedcaddyfortraefikin the stack components table, log commands and cleanup instructions, and fixedselfhosted-guidecalling the bundled proxy Caddy in one place while calling it Traefik in another.Consequences that were previously unstated: a peer that does not trust a private issuing CA fails to connect outright rather than warning;
config.yaml's emptyserver.tlsblock is intentional becausenetbird-serverlistens on plain HTTP behind Traefik; and dropping the80:80mapping is fine for certificates but costs the HTTP→HTTPS redirect.Out of scope
external-reverse-proxyand the installer's "External Caddy" menu option are unchanged — those correctly describe an operator's own Caddy.maintenance/backupandmigration/external-to-embedded-idpstill reference the pre-v0.65 five-container layout, which is a separate cleanup.Summary by CodeRabbit