You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Fix reverse proxy docs: add ProxyService gRPC route, fix container commands, support both setups
- add missing /management.ProxyService/ gRPC route to all reverse proxy config templates (traefik, nginx, caddy, NPM) in reverse-proxy.mdx
- change default proxy -> management connection to use direct docker network instead of routing through traefik, avoiding hairpin NAT and missing gRPC route issues
- add "Connecting through Traefik" section for separatevhost deployments
- fix token CLI commands: use /go/bin/ prefix (not on container PATH), add --config flag for combined container
- ratify instructions for enabling reverse proxy both combined (netbird-server) and multi-container (management) setups
* remove unecessary proxy endpoints from reverse proxy templates other than traefik in reverse-proxy.mdx
* - standardize usage of 'docker exec' as opposed to 'docker compose exec + service name' in instructions
- added AuthClientID config instructions
- added traefik grpc rule to configuration file explanation page
- idletimeout for reverse proxy migration is now 0, matching getting-started.sh
* add clarification on grpc ProxyService path for traffic - only required if the proxy service is on a different docker network to traefik
* fix: correct step count in Traefik connection section from two to three
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Jack Carter <128555021+SunsetDrifter@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
| `netbird-grpc` | `/signalexchange.SignalExchange/`, `/management.ManagementService/`| `netbird-server-h2c` (h2c scheme) | gRPC traffic for signal exchange and management API. Uses HTTP/2 cleartext (h2c) backend because gRPC requires HTTP/2. |
200
+
| `netbird-grpc` | `/signalexchange.SignalExchange/`, `/management.ManagementService/`, `/management.ProxyService/` | `netbird-server-h2c` (h2c scheme) | gRPC traffic for signal exchange, management API, and the [Reverse Proxy feature](/manage/reverse-proxy). Uses HTTP/2 cleartext (h2c) backend because gRPC requires HTTP/2. The `/management.ProxyService/` path is only needed if the reverse proxy container connects through Traefik (see comment in the snippet above). |
@@ -29,23 +29,27 @@ If your current deployment uses a reverse proxy other than Traefik, you'll need
29
29
30
30
### What stays the same
31
31
32
-
- Your existing `netbird-server`, `dashboard`, `signal`, and `relay` services are unchanged
33
-
- Your `management.json`and other configuration files require no modifications —**unless** you use an external identity provider (not the embedded IdP). See [Configure SSO for external identity providers](#configure-sso-for-external-identity-providers) below.
32
+
- Your existing NetBird services are unchanged
33
+
- Your configuration files (`config.yaml` for combined setup, `management.json`for multi-container setup) require no modifications -**unless** you use an external identity provider (not the embedded IdP). See [Configure SSO for external identity providers](#configure-sso-for-external-identity-providers) below.
34
34
- Existing peers, networks, and access policies are unaffected
35
35
36
36
## Prerequisites
37
37
38
38
Before starting, ensure you have:
39
39
40
40
-**Traefik** as your reverse proxy (see [Why Traefik is required](#why-traefik-is-required) above)
41
-
-**Latest `netbird-server` image** - pull the latest version to ensure the management CLI supports token creation
41
+
-**Latest NetBird images** - pull the latest version to ensure the management server and CLI support the reverse proxy feature and token creation
42
42
-**A domain for the proxy** - e.g., `proxy.example.com`. Service subdomains will be created under this domain (e.g., `myapp.proxy.example.com`)
43
43
-**Wildcard DNS capability** - ability to create a `*.proxy.example.com` DNS record pointing to your server
44
+
-**Port 443 accessible** - the proxy needs this for ACME TLS-ALPN-01 challenges (certificate provisioning)
45
+
46
+
<Note>
47
+
This guide covers both the **combined container** setup (`netbirdio/netbird-server`, the default for new deployments) and the **multi-container** setup (separate `management`, `signal`, and `relay` images). Where commands or configuration differ between the two setups, both variants are shown.
48
+
</Note>
44
49
45
50
<Warning>
46
51
The proxy domain **must not** be a subdomain of your NetBird management domain. For example, if your management server is at `netbird.example.com`, do not use `proxy.netbird.example.com`. Use a separate subdomain like `proxy.example.com` instead. Using a subdomain of the management domain causes TLS and routing conflicts between the proxy and management services.
47
52
</Warning>
48
-
-**Port 443 accessible** - the proxy needs this for ACME TLS-ALPN-01 challenges (certificate provisioning)
49
53
50
54
## Migration steps
51
55
@@ -58,44 +62,60 @@ cd netbird-backup-$(date +%Y%m%d)
This outputs a token in the format `nbx_...` (40 characters). **Save the token immediately** - it is only displayed once. The management server stores only a SHA-256 hash.
74
88
75
89
You can manage tokens later with:
76
90
77
91
```bash
78
-
# List all tokens
79
-
docker exec -it netbird-server netbird-mgmt token list
92
+
# List all tokens (combined container)
93
+
docker exec -it netbird-server /go/bin/netbird-server token list \
94
+
--config <netbird-data-dir>/config.yaml
95
+
96
+
# List all tokens (multi-container)
97
+
docker exec -it netbird-management /go/bin/netbird-mgmt token list
### Step 3: Add the proxy service to docker-compose.yml
86
108
87
-
Add the following service to your `docker-compose.yml`. Replace the placeholder values with your actual domains:
109
+
Add the following service to your `docker-compose.yml`. Adjust the `depends_on` value to match your management service name:
88
110
89
111
```yaml
90
112
proxy:
91
113
image: netbirdio/reverse-proxy:latest
92
114
container_name: netbird-proxy
93
-
extra_hosts:
94
-
- "netbird.example.com:172.30.0.10"
95
115
restart: unless-stopped
96
116
networks: [netbird]
97
117
depends_on:
98
-
- netbird-server
118
+
- netbird-server# Use "management" for multi-container setup
99
119
env_file:
100
120
- ./proxy.env
101
121
volumes:
@@ -123,21 +143,41 @@ volumes:
123
143
netbird_proxy_certs:
124
144
```
125
145
126
-
Replace `netbird.example.com` in the `extra_hosts` entry with your actual NetBird management domain. This hairpin NAT fix ensures the proxy can reach Traefik's static IP within the Docker network.
146
+
Then create a `proxy.env` file with the proxy configuration.
127
147
128
-
Then create a `proxy.env` file with the proxy configuration:
Replace `proxy.example.com` with your proxy domain and `netbird.example.com` with your management domain.
174
+
Replace `proxy.example.com` with your proxy domain. The `NB_PROXY_MANAGEMENT_ADDRESS` must match the Docker Compose service name and port of your management server - `netbird-server:80` for the combined container, or `management:33073` for the multi-container Traefik setup.
175
+
176
+
<Note>
177
+
The proxy connects to the management server directly over the Docker network rather than through Traefik. This avoids the need to route the `/management.ProxyService/` gRPC service through your reverse proxy and eliminates hairpin NAT issues. The `NB_PROXY_ALLOW_INSECURE=true` setting is safe here because the traffic never leaves the Docker network.
178
+
179
+
If your proxy and management server run on **separate hosts** and cannot communicate over a shared Docker network, see [Connecting through Traefik](#connecting-through-traefik-instead-of-docker-network) below.
180
+
</Note>
141
181
142
182
The Traefik labels configure a **TCP router** that:
143
183
- Catches any request not matched by higher-priority HTTP routers via `HostSNI(*)` (wildcard)
@@ -152,7 +192,7 @@ The `HostSNI(*)` rule acts as a catch-all for any domain not matched by the exis
152
192
153
193
### Step 4: Set up DNS records
154
194
155
-
Create two DNS records pointing to the server running your NetBird stack — one for the base proxy domain and one wildcard for service subdomains:
195
+
Create two DNS records pointing to the server running your NetBird stack - one for the base proxy domain and one wildcard for service subdomains:
156
196
157
197
| Type | Name | Content |
158
198
|------|------|---------|
@@ -194,7 +234,7 @@ If the domain appears, the proxy is connected and ready. You can now [create you
194
234
195
235
### Who this applies to
196
236
197
-
This section applies to deployments using a **standalone external identity provider** (Auth0, Okta, Keycloak, Zitadel, etc.) instead of the built-in embedded IdP (Dex). If you deployed using the quickstart script with default settings, you are using the embedded IdP and can skip this section.
237
+
This section applies to **multi-container** deployments using a **standalone external identity provider** (Auth0, Okta, Keycloak, Zitadel, etc.) instead of the built-in embedded IdP (Dex). If you are running the combined container or deployed using the quickstart script with default settings, you are using the embedded IdP and can skip this section - the callback is registered automatically.
198
238
199
239
### Why this is needed
200
240
@@ -206,16 +246,17 @@ If you want to keep using your current external identity provider, follow these
206
246
207
247
#### Step 1: Add callback URL to management.json
208
248
209
-
Add the `AuthCallbackURL` field to the `HttpConfig` section of your `management.json`:
249
+
Add the `AuthCallbackURL` and `AuthClientID` fields to the `HttpConfig` section of your `management.json`:
Replace `<your-management-domain>` with your NetBird management server domain (the same domain used for the dashboard).
259
+
Replace `<your-management-domain>` with your NetBird management server domain (the same domain used for the dashboard). Replace `<your-auth-client-id>` with the OAuth2 client ID from your identity provider (the same client ID used for the dashboard application).
219
260
220
261
#### Step 2: Register callback in your IdP
221
262
@@ -242,12 +283,12 @@ Where to find this setting in common providers:
242
283
Restart the management service to pick up the configuration change:
243
284
244
285
```bash
245
-
docker compose restart netbird-management
286
+
docker compose restart management
246
287
```
247
288
248
289
### Option B: Migrate to the embedded IdP (recommended)
249
290
250
-
The embedded IdP (Dex) handles the reverse proxy callback registration automatically — no manual configuration needed. If you want a simpler setup, consider migrating to the embedded IdP.
291
+
The embedded IdP (Dex) handles the reverse proxy callback registration automatically - no manual configuration needed. If you want a simpler setup, consider migrating to the embedded IdP.
251
292
252
293
With the embedded IdP, external identity providers can still be used as **connectors** alongside local authentication. This means your users can continue to sign in with their existing accounts (Google, Okta, Keycloak, etc.) while the embedded IdP manages the OIDC layer.
253
294
@@ -268,6 +309,94 @@ After configuring SSO for your external identity provider, verify it works:
268
309
269
310
If the redirect fails or you see an error from your IdP, double-check that the callback URL is correctly registered in both `management.json` and your identity provider's settings.
270
311
312
+
## Connecting through Traefik instead of Docker network
313
+
314
+
If your proxy container cannot reach the management container directly - for example, if they run on **separate hosts** - you can route the proxy's management connection through Traefik instead. This requires three additional configuration steps.
315
+
316
+
### 1. Add the ProxyService gRPC route
317
+
318
+
The proxy communicates with the management server over two gRPC services: `ManagementService`and `ProxyService`. Both paths must be routed through Traefik. Find the existing gRPC router label in your `docker-compose.yml` - in a standard deployment this is `traefik.http.routers.netbird-grpc` - and add the `ProxyService` path prefix:
Without the `/management.ProxyService/` route, the proxy will fail to register with the management server.
325
+
326
+
### 2. Fix the Traefik container IP for hairpin NAT
327
+
328
+
When the proxy connects to your management domain through Traefik, the DNS resolution inside the Docker network must point to the Traefik container. This is done via an `extra_hosts` entry in the proxy service, but the IP address must match Traefik's actual IP.
329
+
330
+
To ensure a stable IP, assign a static IP to the Traefik container within your Docker network:
331
+
332
+
```yaml
333
+
# In your docker-compose.yml
334
+
335
+
networks:
336
+
netbird:
337
+
driver: bridge
338
+
ipam:
339
+
config:
340
+
- subnet: 172.30.0.0/24
341
+
gateway: 172.30.0.1
342
+
343
+
services:
344
+
traefik:
345
+
# ...existing traefik config...
346
+
networks:
347
+
netbird:
348
+
ipv4_address: 172.30.0.10
349
+
```
350
+
351
+
Then add the `extra_hosts` entry to the proxy service referencing that IP:
352
+
353
+
```yaml
354
+
proxy:
355
+
# ...existing proxy config...
356
+
extra_hosts:
357
+
- "netbird.example.com:172.30.0.10"
358
+
```
359
+
360
+
Replace `netbird.example.com` with your actual management domain.
361
+
362
+
### 3. Increase Traefik's idle timeout for gRPC
363
+
364
+
Traefik's default idle timeout (180 seconds) is too short for the long-lived gRPC streams used between the proxy and management server. Without increasing it, the proxy will report connection timeout errors and the dashboard may show the proxy agent as offline.
365
+
366
+
Add the following to your Traefik static configuration:
# Do NOT set NB_PROXY_ALLOW_INSECURE when connecting over TLS through Traefik
394
+
```
395
+
396
+
<Warning>
397
+
If you do not assign a static IP to Traefik, Docker may assign a different IP on container restart, and the `extra_hosts` entry will silently point to the wrong address. Always configure a fixed subnet and static IP when using this approach.
398
+
</Warning>
399
+
271
400
## For users not on Traefik
272
401
273
402
If your self-hosted deployment currently uses Nginx, Caddy, or another reverse proxy, you'll need to switch to Traefik before enabling the Reverse Proxy feature. See the [Traefik setup instructions](/selfhosted/reverse-proxy#traefik) for a step-by-step guide on configuring Traefik for your NetBird deployment.
@@ -276,7 +405,7 @@ If your self-hosted deployment currently uses Nginx, Caddy, or another reverse p
276
405
277
406
| Variable | Required | Description | Default |
278
407
|----------|----------|-------------|---------|
279
-
| `NB_PROXY_TOKEN` | Yes | Access token generated via `netbird-mgmt token create`. The proxy refuses to start without it. | - |
408
+
| `NB_PROXY_TOKEN` | Yes | Access token generated via `netbird-server token create` (combined) or `netbird-mgmt token create` (multi-container). The proxy refuses to start without it. | - |
280
409
| `NB_PROXY_DOMAIN` | Yes | Base domain for this proxy instance (e.g., `proxy.example.com`). Determines the domain available for services. | - |
281
410
| `NB_PROXY_MANAGEMENT_ADDRESS` | No | URL of your NetBird management server. The proxy connects via gRPC to register itself. | `https://api.netbird.io:443` |
282
411
| `NB_PROXY_ADDRESS` | No | Address the proxy listens on. | `:8443` (Docker), `:443` (binary) |
@@ -342,8 +471,15 @@ docker compose up -d
342
471
You can also revoke the proxy token to prevent the proxy from reconnecting:
343
472
344
473
```bash
345
-
docker exec -it netbird-server netbird-mgmt token list
|`/management.ProxyService/*`| gRPC | management:80 | HTTP/2 (h2c) required. Only needed if using the [Reverse Proxy feature](/manage/reverse-proxy). |
0 commit comments