diff --git a/src/pages/selfhosted/enterprise/getting-started.mdx b/src/pages/selfhosted/enterprise/getting-started.mdx
index 6f50f7446..d94318d3f 100644
--- a/src/pages/selfhosted/enterprise/getting-started.mdx
+++ b/src/pages/selfhosted/enterprise/getting-started.mdx
@@ -95,7 +95,7 @@ The combined stack:
| Service | Image | Notes |
| --- | --- | --- |
-| `traefik` | `traefik:v3.6` | TLS termination, reverse proxy, HTTP→HTTPS redirect |
+| `traefik` | `traefik:v3.7.18` | TLS termination, reverse proxy, HTTP→HTTPS redirect |
| `dashboard` | `ghcr.io/netbirdio/dashboard-cloud:latest` | UI |
| `postgres` | `postgres:17` | Datastore for management, embedded IdP, traffic events |
| `netbird-server` | `ghcr.io/netbirdio/netbird-server-cloud:latest` | Management + signal + relay + embedded STUN on UDP/3478 |
diff --git a/src/pages/selfhosted/external-reverse-proxy.mdx b/src/pages/selfhosted/external-reverse-proxy.mdx
index e3d2d0e57..8a8568b6c 100644
--- a/src/pages/selfhosted/external-reverse-proxy.mdx
+++ b/src/pages/selfhosted/external-reverse-proxy.mdx
@@ -804,29 +804,47 @@ entryPoints:
scheme: https
```
+**5. No timeouts on the `websecure` entrypoint.** Without these settings, Traefik resets each peer's Signal connection every 60 seconds and the peer has to reconnect:
+```yaml
+# As command args
+- "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
+- "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0"
+- "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0"
+```
+
+**6. Header handling** (Traefik v3.7.18 or later: earlier v3.7 releases are affected by published Traefik security advisories, and releases before v3.7.12 fail to start with these settings). See [Traefik header handling](/selfhosted/maintenance/upgrade#traefik-header-handling):
+```yaml
+# As command args
+- "--entrypoints.web.http.aliasHeadersStrategy=delete"
+- "--entrypoints.websecure.http.aliasHeadersStrategy=delete"
+```
+
##### Example Traefik Docker Compose
-If you don't have Traefik set up yet, here's a complete example:
+If you don't have Traefik set up yet, use this example:
```yaml
services:
traefik:
- image: traefik:v3.2
+ image: traefik:v3.7.18
command:
- - "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedByDefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
+ - "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
+ - "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0"
+ - "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0"
+ - "--entrypoints.web.http.aliasHeadersStrategy=delete"
+ - "--entrypoints.websecure.http.aliasHeadersStrategy=delete"
- "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
- - "8080:8080" # Traefik dashboard (optional)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
@@ -838,6 +856,8 @@ networks:
name: traefik-network
```
+The example pins `traefik:v3.7.18`. Requirements 5 and 6 above cover the example's two NetBird-specific groups of settings.
+
When using `getting-started.sh` with Traefik, the script will ask for your network name, entrypoint, and certresolver. It will then generate a docker-compose.yml with all the correct labels pre-configured.
diff --git a/src/pages/selfhosted/identity-providers/local.mdx b/src/pages/selfhosted/identity-providers/local.mdx
index 02c87c1f3..9d1f53269 100644
--- a/src/pages/selfhosted/identity-providers/local.mdx
+++ b/src/pages/selfhosted/identity-providers/local.mdx
@@ -73,27 +73,46 @@ For a full list of available configuration options, see the [config.yaml.example
This section applies to deployments using the older multi-container architecture. If you deployed using `getting-started.sh`, you are on the combined setup and should use the `config.yaml` instructions above. See the [migration guide](/selfhosted/migration/combined-container) to upgrade.
-Update your `management.json`:
+
+Use this section only on a new deployment that has no users yet. It does not move existing users. On a deployment that already has users from another identity provider, Management starts, but the embedded identity provider has none of them and the dashboard's first-user setup page does not appear, so nobody can sign in. To switch such a deployment, follow [Migration Guide: External IdP to Embedded IdP](/selfhosted/migration/external-to-embedded-idp) instead.
+
+
+Add or change these keys in your `management.json` and keep its other keys (the last note below says when to delete `HttpConfig`). In this block and the dashboard block below, replace `netbird.example.com` with your domain:
```json
{
+ "DataStoreEncryptionKey": "",
"EmbeddedIdP": {
"Enabled": true,
- "DataDir": "/var/lib/netbird/idp"
- },
- "EncryptionKey": ""
+ "Issuer": "https://netbird.example.com/oauth2",
+ "DashboardRedirectURIs": [
+ "https://netbird.example.com/nb-auth",
+ "https://netbird.example.com/nb-silent-auth"
+ ],
+ "SessionCookieEncryptionKey": ""
+ }
}
```
-Or configure via environment variables on the `management` container:
+The dashboard must use the same values. In the dashboard container's environment ([dashboard.env](/selfhosted/maintenance/configuration-files#dashboardenv)), set these lines. `AUTH_AUTHORITY` is the `Issuer` above, `AUTH_REDIRECT_URI` and `AUTH_SILENT_REDIRECT_URI` are the paths of the two `DashboardRedirectURIs`, and `AUTH_CLIENT_SECRET` stays empty:
-```yaml
-environment:
- - NETBIRD_EMBEDDED_IDP_ENABLED=true
- - NETBIRD_EMBEDDED_IDP_DATA_DIR=/var/lib/netbird/idp
- - NETBIRD_ENCRYPTION_KEY=${ENCRYPTION_KEY}
+```bash
+AUTH_AUDIENCE=netbird-dashboard
+AUTH_CLIENT_ID=netbird-dashboard
+AUTH_CLIENT_SECRET=
+AUTH_AUTHORITY=https://netbird.example.com/oauth2
+USE_AUTH0=false
+AUTH_SUPPORTED_SCOPES=openid profile email groups
+AUTH_REDIRECT_URI=/nb-auth
+AUTH_SILENT_REDIRECT_URI=/nb-silent-auth
```
+- **`Issuer` is required.** Without it, Management exits at startup with `issuer is required`.
+- **Your reverse proxy must route `/oauth2/*` to Management.** The embedded identity provider is served there, and the dashboard sends sign-ins to the `Issuer` URL.
+- **`DataStoreEncryptionKey`:** if your `management.json` already has one, keep it, because the stored data is encrypted with it. Otherwise, generate one with `openssl rand -base64 32`. If you leave it empty, Management generates one and writes it into `management.json`; with the file mounted read-only, Management exits with `failed to save config with new encryption key`. Back up `management.json` once it holds the key.
+- **`SessionCookieEncryptionKey`:** generate one with `openssl rand -base64 32`. Without it, the embedded IdP's session cookie is not encrypted.
+- **A leftover `HttpConfig` section** does not stop Management from starting. Management overrides its identity provider fields and logs the warning `overriding HttpConfig with EmbeddedIdP config`. If the section sets `LetsEncryptDomain`, or `CertFile` and `CertKey`, keep the section: Management still uses those keys for its own TLS and keeps running with the warning. If it sets neither, delete the section to clear the warning.
+
### Generating an Encryption Key
If you need to generate an encryption key manually:
diff --git a/src/pages/selfhosted/maintenance/configuration-files.mdx b/src/pages/selfhosted/maintenance/configuration-files.mdx
index dd269ffcb..a5aed3888 100644
--- a/src/pages/selfhosted/maintenance/configuration-files.mdx
+++ b/src/pages/selfhosted/maintenance/configuration-files.mdx
@@ -43,7 +43,7 @@ The Docker Compose file defines all NetBird services, their dependencies, networ
| Service | Image | Internal Port | External (Exposed) | Description |
|---------|-------|---------------|-------------------|-------------|
-| `traefik` | `traefik:v3.6` | 80, 443 | 80:80, 443:443 | Handles TLS termination via Let's Encrypt and routes incoming HTTPS requests to the appropriate NetBird services. Only included when using the built-in Traefik option (option 0). |
+| `traefik` | `traefik:v3.7.18` | 80, 443 | 80:80, 443:443 | Handles TLS termination via Let's Encrypt and routes incoming HTTPS requests to the appropriate NetBird services. Only included when using the built-in Traefik option (option 0). |
| `dashboard` | `netbirdio/dashboard` | 80 | 8080:80 | The web-based management console where administrators configure networks, manage peers, create access policies, and view activity logs. Includes an embedded nginx server for serving the UI. |
| `netbird-server` | `netbirdio/netbird-server` | 80, 3478/udp | 8081:80, 3478:3478/udp | Combined server that includes management, signal, relay, and embedded STUN in a single container. Configured via `config.yaml`. |
@@ -57,21 +57,27 @@ The `netbird-server` container combines what were previously separate management
### Traefik Service
-The Traefik service is only present when using the built-in reverse proxy option (option 0 during setup). It handles automatic TLS certificate provisioning via Let's Encrypt and routes requests to the correct backend services.
+The Traefik service is only present when using the built-in reverse proxy option (option 0 during setup).
```yaml
traefik:
- image: traefik:v3.6
+ image: traefik:v3.7.18
container_name: netbird-traefik
restart: unless-stopped
- networks: [netbird]
+ networks:
+ netbird:
+ ipv4_address: 172.30.0.10
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- - "--providers.docker.network=netbird"
+ - "--providers.docker.network=${COMPOSE_PROJECT_NAME:-}_netbird"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
+ - "--entrypoints.web.http.aliasHeadersStrategy=delete"
+ - "--entrypoints.websecure.http.aliasHeadersStrategy=delete"
- "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
+ - "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0"
+ - "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
@@ -90,7 +96,7 @@ traefik:
```
-The `readTimeout=0` setting on the websecure entrypoint disables read timeouts, which is required for long-lived gRPC and WebSocket connections used by the signal and relay services.
+Without the three `respondingTimeouts` settings, Traefik resets each peer's long-lived Signal connection every 60 seconds and the peer has to reconnect. The installers require Traefik v3.7.13 or later for the `aliasHeadersStrategy` settings; see [Traefik header handling](/selfhosted/maintenance/upgrade#traefik-header-handling).
### Dashboard Service
diff --git a/src/pages/selfhosted/maintenance/crowdsec-dashboard.mdx b/src/pages/selfhosted/maintenance/crowdsec-dashboard.mdx
index dd9699d2c..581553ba7 100644
--- a/src/pages/selfhosted/maintenance/crowdsec-dashboard.mdx
+++ b/src/pages/selfhosted/maintenance/crowdsec-dashboard.mdx
@@ -134,12 +134,12 @@ Start from the `docker-compose.yml` generated by the quickstart with proxy Crowd
- After manual setup, set `NETBIRD_CROWDSEC_APPSEC_ENABLED=yes` in `.env` before rerunning the enterprise script with `--enable-proxy` or `--enable-traffic-events`.
-For quickstart installs, set the Traefik image to the validated version below. Add the header handling and bouncer plugin arguments to the existing `services.traefik.command` list:
+For quickstart installs, set the Traefik image to `v3.7.18`. Add the header handling and bouncer plugin arguments to the existing `services.traefik.command` list:
```yaml
services:
traefik:
- image: traefik:v3.7.14
+ image: traefik:v3.7.18
command:
- '--entrypoints.web.http.aliasHeadersStrategy=delete'
- '--entrypoints.websecure.http.aliasHeadersStrategy=delete'
diff --git a/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx b/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx
index b65484c87..a3c3c6ae4 100644
--- a/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx
+++ b/src/pages/selfhosted/maintenance/scaling/multiple-proxy-instances.mdx
@@ -163,7 +163,7 @@ Create a `docker-compose.yml` on the new server:
```yaml
services:
traefik:
- image: traefik:v3.6
+ image: traefik:v3.7.18
container_name: traefik
restart: unless-stopped
command:
diff --git a/src/pages/selfhosted/maintenance/upgrade.mdx b/src/pages/selfhosted/maintenance/upgrade.mdx
index 444707fda..63734714d 100644
--- a/src/pages/selfhosted/maintenance/upgrade.mdx
+++ b/src/pages/selfhosted/maintenance/upgrade.mdx
@@ -86,23 +86,21 @@ Traefik and CrowdSec have their own release cycles. Upgrading NetBird does not u
### Choosing versions
-The following dependency versions have been validated for self-hosted NetBird as of **October 9, 2026**:
+The following version pins are used in these self-hosted NetBird examples:
-| Component | Validated version |
+| Component | Version |
| --- | --- |
-| Bundled Traefik | `traefik:v3.7.14` |
+| Bundled Traefik | `traefik:v3.7.18` |
| CrowdSec | `crowdsecurity/crowdsec:v1.8.1` |
| Traefik CrowdSec bouncer plugin | `v1.7.1` |
-Installer defaults can differ from these versions. Check the image tags in your `docker-compose.yml`; the bouncer plugin is configured separately in the [dashboard AppSec guide](/selfhosted/maintenance/crowdsec-dashboard#update-docker-compose-yml). Before adopting a newer release, review its migration requirements and verify it with your NetBird configuration in a test deployment.
-
- **Traefik:** check the [releases](https://github.com/traefik/traefik/releases), [support policy](https://doc.traefik.io/traefik/deprecation/releases/), and [v3 migration notes](https://doc.traefik.io/traefik/migrate/v3/). Configuration changes can be required within the same major version.
- **CrowdSec:** check the [releases](https://github.com/crowdsecurity/crowdsec/releases) and [Docker documentation](https://docs.crowdsec.net/u/getting_started/installation/docker/).
- **Dashboard AppSec:** also check the [Traefik bouncer plugin releases](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/releases). The plugin version is set by `--experimental.plugins.bouncer.version` in Traefik's `command:` list. Changing the CrowdSec image does not update it. A new installation can turn AppSec on from the quickstart or the enterprise script. The quickstart never changes an existing install, and the enterprise script adds AppSec only together with the proxy through `--enable-proxy`. To add AppSec to a running proxy, follow the [dashboard guide](/selfhosted/maintenance/crowdsec-dashboard).
You can subscribe to release notifications on each GitHub repository using **Watch → Custom → Releases**. Check security advisories and upstream support status as well as the installer defaults when planning updates.
-Full version tags such as `traefik:v3.7.14` and `crowdsecurity/crowdsec:v1.8.1` select specific releases. A minor-version tag such as `traefik:v3.6` can fetch a newer patch image without a Compose edit. For controlled rollouts, use full version tags for all images, or image digests when you need immutable references, and update them deliberately after validation.
+Full version tags such as `traefik:v3.7.18` and `crowdsecurity/crowdsec:v1.8.1` select specific releases. A minor-version tag such as `traefik:v3.7` can fetch a newer patch image without a Compose edit. For controlled rollouts, use full version tags for all images, or image digests when you need immutable references, and update them deliberately after validation.
### Before changing a version
@@ -133,6 +131,8 @@ Full version tags such as `traefik:v3.7.14` and `crowdsecurity/crowdsec:v1.8.1`
Change one component at a time so you can identify regressions. Edit that service's `image:` in `docker-compose.yml` to the version or digest you selected, preserving its existing environment, labels, networks, and volume mounts. If the image is supplied through a Compose variable, update that variable instead.
+For this Traefik update, set `image: traefik:v3.7.18` on the `traefik` service in a quickstart installation. For an enterprise installation using `image: traefik:${NETBIRD_TRAEFIK_TAG}`, set `NETBIRD_TRAEFIK_TAG=v3.7.18` in the Compose project's `.env` file.
+
For Traefik, also check [header handling](#traefik-header-handling) and the [Docker network setting](#traefik-docker-network) before recreating the container.
Validate the configuration before applying it:
@@ -182,12 +182,12 @@ Record the exact image versions or digests, plugin version, and test results wit
### Roll back a dependency update
-Restore the previous image digest or full version tag and any configuration changed for that component, including the bouncer plugin version. Recreate the affected service with `docker compose up -d --no-deps ` and repeat the verification checks. Restoring a moving tag such as `v3.6` or `latest` may fetch the upgraded image again; use the recorded digest to recover the exact previous image.
+Restore the previous image digest or full version tag and any configuration changed for that component, including the bouncer plugin version. Recreate the affected service with `docker compose up -d --no-deps ` and repeat the verification checks. Restoring a moving tag such as `v3.7` or `latest` may fetch the upgraded image again; use the recorded digest to recover the exact previous image.
When rolling Traefik back to a release older than `v3.7.12`, also remove the `aliasHeadersStrategy` flags added in [Traefik header handling](#traefik-header-handling). Those releases do not recognize the option and fail to start with `field not found, node: aliasHeadersStrategy`.
-Traefik v3.0.0 through v3.7.11 are affected by header-alias spoofing ([GHSA-rf44-j88r-hh8c](https://github.com/traefik/traefik/security/advisories/GHSA-rf44-j88r-hh8c)). Removing `aliasHeadersStrategy` so those releases can start restores that vulnerable handling: a client can send an alias of a header Traefik wrote, and a backend that treats those names as the same variable can read the client's value instead. Do not expose an affected rollback version to untrusted traffic. Return to `v3.7.12` or newer, with `aliasHeadersStrategy` set to `delete`, once service is restored.
+Traefik v3.0.0 through v3.7.11 are affected by header-alias spoofing ([GHSA-rf44-j88r-hh8c](https://github.com/traefik/traefik/security/advisories/GHSA-rf44-j88r-hh8c)). Removing `aliasHeadersStrategy` so those releases can start restores that vulnerable handling: a client can send an alias of a header Traefik wrote, and a backend that treats those names as the same variable can read the client's value instead. Do not expose an affected rollback version to untrusted traffic. Return to `v3.7.18` or a newer release you have verified, with `aliasHeadersStrategy` set to `delete`, once service is restored.
If the release migrated stored data or configuration in a way the older version cannot read, stop the affected service and [restore its pre-upgrade backup](/selfhosted/maintenance/backup) before starting the older image. Changing an image tag does not undo a database migration.
@@ -196,7 +196,7 @@ If the release migrated stored data or configuration in a way the older version
### Traefik header handling
-Traefik v3.7.12 introduced `aliasHeadersStrategy` and warns when it is unset. When upgrading to the validated `v3.7.14` version, add these settings to the existing `services.traefik.command` list in `docker-compose.yml`:
+Traefik v3.7.12 introduced `aliasHeadersStrategy` and warns when it is unset. The installers require at least `v3.7.13` for the option's header-sanitization fix. When upgrading to `v3.7.18`, add these settings to the existing `services.traefik.command` list in `docker-compose.yml`:
```yaml
- '--entrypoints.web.http.aliasHeadersStrategy=delete'
diff --git a/src/pages/selfhosted/migration/combined-container.mdx b/src/pages/selfhosted/migration/combined-container.mdx
index 66b515972..81af26bac 100644
--- a/src/pages/selfhosted/migration/combined-container.mdx
+++ b/src/pages/selfhosted/migration/combined-container.mdx
@@ -22,7 +22,7 @@ The migration script **exits with an error** if it detects an external identity
### What's new
- **Combined `netbird-server` container** - management, signal, relay, and the embedded STUN server all run in a single container, replacing four separate services
-- **Traefik reverse proxy** (for Caddy-based setups) - replaces the embedded Caddy with Traefik v3.6, handling TLS termination via Let's Encrypt and routing for gRPC, WebSocket, and HTTP traffic
+- **Traefik reverse proxy** (for Caddy-based setups) - replaces the embedded Caddy with Traefik v3.7.18, handling TLS termination via Let's Encrypt and routing for gRPC, WebSocket, and HTTP traffic
- **Unified `config.yaml`** - a single configuration file replaces the combination of `management.json`, `setup.env`, and multiple environment files
- **Simplified Docker Compose** - the stack goes from 5+ services down to 2 (Traefik + `netbird-server`) or 3 (with dashboard)