Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/pages/selfhosted/maintenance/configuration-files.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ See an example `config.yaml` file in the [NetBird GitHub repository](https://git
Where to write log output. Use `console` for Docker logging (recommended) or specify a file path. Default: `console`.
</Property>
<Property name="server.authSecret" type="string">
Shared secret for relay authentication. Auto-generated by the setup script. This secret is used internally by the combined server for relay credential validation.
Shared secret for relay authentication. Auto-generated by the setup script. This secret is used internally by the combined server for relay credential validation. When `relays.addresses` is configured and `relays.secret` matches this value, the embedded relay stays active alongside external relays. Mismatched values disable the embedded relay and log a warning.
</Property>
<Property name="server.dataDir" type="string">
Data directory path where the server stores its database and state files. Default: `/var/lib/netbird`. Maps to the `netbird_data` Docker volume.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,12 @@ Tell peers where to find STUN through `server.stuns` in the Management configura

Every Management replica's `config.yaml` references the Relay pool through a **single load balancer URL** in `server.relays.addresses`. The load balancer distributes traffic across Relay instances, so this list always has one entry. Configure STUN separately under `server.stuns`:

> If `server.authSecret` is set on the Management replicas and `relays.secret` matches it, the embedded relay in the Management process stays active and its address is automatically prepended to the peer relay list. This is optional; the external relay pool still handles the bulk of traffic. If you prefer to disable the embedded relay, omit `authSecret` from the Management config.

```yaml
server:
# authSecret: "<optional — keep to leave the embedded relay running>"

# External STUN: per-instance hostnames (option 1) or external STUN/TURN (option 2)
stuns:
- uri: "stun:stun-1.example.com:3478"
Expand All @@ -446,7 +450,7 @@ server:
relays:
addresses:
- "rels://relay.example.com:443"
secret: "<NB_AUTH_SECRET; identical on every Relay instance>"
secret: "<NB_AUTH_SECRET; identical on every relay instance and on every Management replica>"
credentialsTTL: "24h"
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ If deploying multiple relays (e.g., for different regions), repeat the steps abo

## Update Main Server Configuration

Now update your main NetBird server to use the external relays instead of the embedded one.
Now configure your main NetBird server to use the external relays alongside (or instead of) the embedded one.

### Edit config.yaml

Expand All @@ -150,15 +150,57 @@ cd ~/netbird # or wherever your deployment is
nano config.yaml
```

Remove the `authSecret` from the `server` section and add `relays` and `stuns` sections pointing to your external servers. The presence of the `relays` section disables both the embedded relay and the embedded STUN server, so the `stuns` section is required to provide external STUN addresses:
Add `relays` and `stuns` sections pointing to your external servers.

#### Option A: Keep the embedded relay running (recommended)

When `server.authSecret` is set and `relays.secret` matches it, the embedded relay stays active. Its address is automatically prepended to the peer relay list and used first when available. Local STUN also stays on as long as `server.stunPorts` has values (default: `[3478]`):
Comment thread
coderabbitai[bot] marked this conversation as resolved.

```yaml
server:
listenAddress: ":80"
exposedAddress: "https://netbird.example.com:443"
# Keep authSecret to keep the embedded relay active
authSecret: "your-auth-secret"
stunPorts:
- 3478
metricsPort: 9090
healthcheckAddress: ":9000"
logLevel: "info"
logFile: "console"
dataDir: "/var/lib/netbird"

# External STUN servers (your relay servers)
stuns:
- uri: "stun:relay-us.example.com:3478"
proto: "udp"
- uri: "stun:relay-eu.example.com:3478"
proto: "udp"

# External relay servers
relays:
addresses:
- "rels://relay-us.example.com:443"
- "rels://relay-eu.example.com:443"
secret: "your-auth-secret" # Must match server.authSecret
credentialsTTL: "24h"

auth:
issuer: "https://netbird.example.com/oauth2"
# ... rest of auth config
```

#### Option B: Disable the embedded relay

If you prefer to use only external relays, remove `authSecret` from the `server` section. The presence of `relays.addresses` without a matching `authSecret` disables both the embedded relay and the local STUN server, so the `stuns` section is required for STUN:

```yaml
server:
listenAddress: ":80"
exposedAddress: "https://netbird.example.com:443"
# Remove authSecret to disable the embedded relay
# authSecret: ...
# Remove or comment out stunPorts since we're using external STUN
# Remove or comment out stunPorts since STUN is handled externally
# stunPorts:
# - 3478
metricsPort: 9090
Expand Down Expand Up @@ -188,12 +230,12 @@ server:
```

<Warning>
The `secret` under `relays` and the `NB_AUTH_SECRET` on all relay servers **must be identical**. Mismatched secrets will cause relay connections to fail silently.
When `authSecret` is set and `relays.secret` does not match it, the embedded relay is disabled and a warning is logged. The external relays continue working normally.
</Warning>

### Update docker-compose.yml (Optional)

If your main server was exposing STUN port 3478, you can remove it since STUN is now handled by external relays:
If your main server was exposing STUN port 3478 and you chose Option B, you can remove it since STUN is now handled by external relays:

```yaml
netbird-server:
Expand Down Expand Up @@ -225,7 +267,19 @@ docker compose up -d
docker compose logs netbird-server
```

Verify that the embedded relay is disabled and your external relay addresses are listed:
With **Option A** (embedded relay kept), you should see the embedded relay is active and your external relay addresses are also listed:

```
INFO combined/cmd/root.go: Management: true (log level: info)
INFO combined/cmd/root.go: Signal: true (log level: info)
INFO combined/cmd/root.go: Relay: true (log level: info)
```

```
Relay addresses: [rels://<embedded>, rels://relay-us.example.com:443 rels://relay-eu.example.com:443]
```

With **Option B** (embedded relay disabled), you should see the embedded relay is disabled:

```
INFO combined/cmd/root.go: Management: true (log level: info)
Expand All @@ -245,7 +299,7 @@ Connect a NetBird client and verify that both STUN and relay services are availa
netbird status -d
```

The output should list your external STUN and relay servers. All configured STUN servers will appear, but only one randomly chosen relay is used per client:
With **Option A**, the embedded relay address appears first in the relay list and is tried first, and the local STUN also appears alongside external STUN servers. With **Option B**, only external servers are listed. All configured STUN servers and relay addresses will appear. Relays are tried in list order — the first available relay is used:

```
Relays:
Expand Down
4 changes: 2 additions & 2 deletions src/pages/selfhosted/observability/combined.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ The combined `/metrics` endpoint returns the union of:

- All [Management metrics](/selfhosted/observability/management) — `management_*` series.
- All [Signal metrics](/selfhosted/observability/signal), each one rewritten with a `signal_` prefix so it doesn't collide with the rest of the endpoint. For example, standalone Signal exposes `active_peers` and `messages_forwarded_total`; in the combined container these become `signal_active_peers` and `signal_messages_forwarded_total`.
- All [Relay metrics](/selfhosted/observability/relay) — `relay_*` series. Emitted only when the embedded relay is enabled (no `relays` override set in `config.yaml`).
- All [Relay metrics](/selfhosted/observability/relay) — `relay_*` series. Emitted when the embedded relay is enabled. The embedded relay is enabled by default when no `relays` override is set, or when `server.authSecret` is set and `relays.secret` matches it. If `relays.addresses` is configured but `relays.secret` does not match `authSecret`, the embedded relay is disabled and its metrics will not appear.

If you point the combined server at an external Signal (`server.signalUri`) or external Relay (`server.relays`), the corresponding local service is disabled and its metrics will not appear on this endpoint — scrape the external service directly instead.
If you point the combined server at an external Signal (`server.signalUri`) or the embedded relay is disabled (as described above), the corresponding local service's metrics will not appear on this endpoint — scrape the external service directly instead.

## Health endpoint

Expand Down