selfhostedops-stack/netbird/README.md

70 lines
2.8 KiB
Markdown

# NetBird - the mesh around the stack (episode 5)
Two containers: the dashboard and a combined server that carries the
management API, the signal service, a relay, STUN and a built-in identity
provider. Everything except one UDP port rides through the same Caddy as the
rest of the stack.
## Install (on the box, next to the stack)
```bash
mkdir -p /opt/netbird && cd /opt/netbird
curl -fsSL https://raw.githubusercontent.com/netbirdio/netbird/main/infrastructure_files/getting-started.sh -o getting-started.sh
NETBIRD_DOMAIN=vpn.example.com \
NETBIRD_REVERSE_PROXY_TYPE=4 \
NETBIRD_EXTERNAL_PROXY_NETWORK=selfhostedops-stack_proxy \
NETBIRD_BIND_LOCALHOST_ONLY=true \
bash getting-started.sh
```
The script renders `docker-compose.yml`, `config.yaml`, `dashboard.env` and
the exact Caddy block to paste (`caddyfile-netbird.txt` - the same block is
already in this repo's `Caddyfile`). Reload Caddy, then open
`https://vpn.example.com`: a one-time setup page asks for the first admin
account. That account lives in the built-in provider and is your break-glass
login - store the password in the vault from episode 4.
## Forgejo as the network's identity provider
1. Forgejo -> Site administration -> Applications -> new OAuth2 application.
Redirect URI: `https://vpn.example.com/oauth2/callback` (confidential client).
2. NetBird dashboard -> Settings -> Identity Providers -> Add Identity Provider.
Type: OIDC (Generic). Issuer: your Forgejo base URL. Paste client ID + secret.
3. The login page now shows "Continue with Forgejo". First-time users land in
*pending approval* until an admin approves them in the Team list.
## Machines join
Servers use setup keys (Settings -> Setup Keys -> Create Key):
```bash
curl -fsSL https://pkgs.netbird.io/install.sh | sh
netbird up --setup-key <KEY> --management-url https://vpn.example.com:443
```
People just run `netbird up --management-url https://vpn.example.com:443`;
the CLI prints a device-code URL, and the browser side is the same
"Continue with Forgejo" button.
## Reaching the containers (and the Docker 28+ trap)
Dashboard -> Networks: add a network, add the compose subnet as a resource
(e.g. `172.18.0.0/16`), add the box itself as routing peer, add one access
policy. Then note the one line already present on the `proxy` network in
`compose.yml`:
```yaml
networks:
proxy:
driver_opts:
com.docker.network.bridge.trusted_host_interfaces: "wt0"
```
Docker 28+ drops any packet to a container IP that does not arrive on
Docker's own bridge (a raw-table rule, so DOCKER-USER does not help). The
option above makes Docker write the accept rules itself. Changing it needs a
network recreate (`docker compose down && docker compose up -d`).
After that, delete a service's public block from the `Caddyfile`, reload
Caddy, and the service is reachable over the mesh only.