* fix: update self-hosted docs for the Traefik reverse proxy `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. * fix: mount the Traefik dynamic config as a directory, not a single file 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. * docs: scope the custom TLS appendix to the fresh enterprise install 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. * docs: apply NetBird house style to the custom TLS appendix 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. * docs: correct the migrate-path guidance in the custom TLS appendix 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. * docs: tighten the custom TLS appendix 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. * docs: find the resolver labels by grep instead of enumerating them 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. * docs: fix three gaps in the custom TLS appendix - 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.
The NetBird documentation
This repository contains assets required to build the documentation website for NetBird. It is built using Next.js with MDX support, a modern React framework for building static and dynamic websites.
We're glad that you want to contribute!
Requirements
- node 16
- npm 8+
Installation
$ npm install
Local Development
$ npm run dev
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
Contributing to the docs
You can click the Fork button in the upper-right area of the screen to create a copy of this repository in your GitHub account. This copy is called a fork. Make any changes you want in your fork, and when you are ready to send those changes to us, go to your fork and create a new pull request to let us know about it.
Once your pull request is created, a NetBird reviewer will take responsibility for providing clear, actionable feedback. As the owner of the pull request, it is your responsibility to modify your pull request to address the feedback that has been provided to you by the NetBird reviewer.
Also, note that you may end up having more than one NetBird reviewer provide you feedback or you may end up getting feedback from a NetBird reviewer that is different than the one initially assigned to provide you feedback.
Furthermore, in some cases, one of your reviewers might ask for a technical review from a NetBird author when needed. Reviewers will do their best to provide feedback in a timely fashion but response time can vary based on circumstances.
Code of conduct
Participation in the NetBird community is governed by the NetBirds' Code of Conduct.
Components and Use
This documentation uses several custom MDX components. Here's a guide to the most commonly used components:
Alert Components
Use these components to highlight important information:
Note
Displays informational content with an orange theme:
import {Note} from "@/components/mdx"
<Note>
NetBird is an **[open-source](https://github.com/netbirdio/netbird)** project and can be self-hosted.
See a comparison between the self-hosted and cloud-hosted versions [here](/selfhosted/self-hosted-vs-cloud-netbird).
</Note>
Warning
Displays warning content with a red theme:
import {Warning} from "@/components/mdx"
<Warning>
The API is still in Beta state so some errors might not be handled properly yet.
</Warning>
Success
Displays success messages with a green theme:
import {Success} from "@/components/mdx"
<Success>
Your configuration has been successfully applied.
</Success>
Tiles Component
Displays a grid of clickable cards with hover effects. Perfect for listing related resources or guides:
import {Tiles} from "@/components/Tiles"
<Tiles
title="About NetBird"
id="about-netbird"
items={[
{
href: '/about-netbird/how-netbird-works',
name: 'How NetBird Works',
description: 'Learn about NetBird concepts, architecture, protocols, and how it creates secure networks.',
},
{
href: '/about-netbird/netbird-vs-traditional-vpn',
name: 'NetBird vs. Traditional VPN',
description: 'Discover how NetBird compares to traditional VPNs and understand the advantages of Zero Trust networking.',
},
]}
/>
Props:
title(string, required): The heading title for the tiles sectionid(string, optional): Optional id for the heading anchoritems(array, required): Array of objects withhref,name, anddescriptionbuttonText(string, optional): Button text (defaults to "Read more" - currently unused as cards are fully clickable)
YouTube Component
Embeds YouTube videos with customizable parameters:
import {YouTube} from "@/components/YouTube"
<YouTube videoId="CFa7SY4Up9k" />
// With custom parameters
<YouTube
videoId="CFa7SY4Up9k"
title="Video Title"
start={175}
color="white"
modestbranding={1}
rel={1}
/>
// Or use a URL instead of videoId
<YouTube url="https://www.youtube.com/watch?v=CFa7SY4Up9k" />
Props:
videoId(string): YouTube video IDurl(string): YouTube URL (alternative to videoId)title(string, optional): Video titlestart(number, optional): Start time in secondscolor(string, optional): Progress bar color -'white'or'red'(default:'white')modestbranding(number, optional): Reduces YouTube branding -0or1(default:1)controls(number, optional): Show/hide controls -0,1, or2(default:1)rel(number, optional): Show related videos -0or1(default:1)
Button Component
Creates styled buttons with multiple variants:
import {Button} from "@/components/Button"
// Primary button (default)
<Button href="https://app.netbird.io/install" arrow="right">
Get started
</Button>
// Secondary button
<Button href="/path" variant="secondary">
Learn more
</Button>
// Outline button
<Button href="/path" variant="outline">
Explore
</Button>
// Text button
<Button href="/path" variant="text" arrow="right">
Read more
</Button>
// With left arrow
<Button href="/path" arrow="left">
Back
</Button>
Props:
variant(string, optional): Button style -'primary','secondary','filled','outline', or'text'(default:'primary')href(string, optional): Link URL (creates a link if provided, otherwise renders as button)arrow(string, optional): Arrow icon -'left'or'right'children(required): Button text content
Other Common Components
Row and Col
Create two-column layouts:
import {Row, Col} from "@/components/mdx"
<Row>
<Col>
Left column content
</Col>
<Col sticky>
Right column content (sticky on scroll)
</Col>
</Row>
Properties and Property
Define API properties or configuration options:
import {Properties, Property} from "@/components/mdx"
<Properties>
<Property name="apiKey" type="string" required>
Your API key for authentication.
</Property>
<Property name="timeout" type="number" min={0} max={300}>
Request timeout in seconds (default: 30).
</Property>
</Properties>
Badge
Displays small status badges:
import {Badge} from "@/components/mdx"
<Badge>New</Badge>
<Badge variant="secondary">Beta</Badge>
Code Blocks
Code syntax highlighting (automatically available):
\`\`\`bash
npm install
npm run dev
\`\`\`
// Or use code groups for multiple languages
<CodeGroup>
```bash title="Installation"
npm install
yarn install
Thank you
NetBird thrives on community participation, and we appreciate your contributions to our website and our documentation!