Documented NetBird-Only Access and Proxy Cluster features in reverse … (#767)
* Documented NetBird-Only Access and Proxy Cluster features in reverse proxy settings. Updated authentication methods, backend configuration guides, and cluster capability requirements. * Expanded documentation for NetBird-Only services, updated Access Control baseline behavior, added details on Direct Upstream and Proxy Cluster features, and refined cluster capability descriptions. * add private services diagrams and update auth screenshot * Document ProxyService gRPC routes and expand reverse proxy configuration details --------- Co-authored-by: TechHutTV <brandon@techhut.tv>
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 340 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 109 KiB |
@@ -13,12 +13,73 @@ NetBird Reverse Proxy supports multiple authentication methods and connection-le
|
||||
|
||||
## Authentication methods
|
||||
|
||||
NetBird offers four authentication methods, each suited to different access patterns. You can enable any combination of them on a single service.
|
||||
NetBird offers two families of authentication, suited to different access patterns:
|
||||
|
||||
- **Operator auth** — SSO, password, PIN, and header authentication. Designed for *public* services where the proxy fronts an internal app for the open internet and you want to gate it with credentials of your choosing. Multiple methods can be enabled on the same service; users pick which one to use.
|
||||
- **NetBird-Only Access** — Designed for *private* services that should never be reachable from the public internet. The proxy only lets in requests that come from a peer in your NetBird network and whose owner belongs to the configured access groups. Available on clusters that advertise the `Private` capability.
|
||||
|
||||
NetBird-Only Access is mutually exclusive with the operator auth methods on the same service. When NetBird-Only is enabled, the SSO/password/PIN/header rows are hidden — the trust boundary is the WireGuard tunnel, not an operator credential.
|
||||
|
||||
<Note>
|
||||
SSO, password, PIN, and header authentication all require HTTP (Layer 7) and are only available for HTTP services. For L4 services (TCP, UDP, TLS), use [access restrictions](#access-restrictions) to control access.
|
||||
All HTTP-layer methods (SSO, password, PIN, header, and NetBird-Only Access) require HTTP (Layer 7) and are only available for HTTP services. For L4 services (TCP, UDP, TLS), use [access restrictions](#access-restrictions) to control access.
|
||||
</Note>
|
||||
|
||||
### NetBird-Only Access (private services)
|
||||
|
||||
NetBird-Only Access restricts the service to peers running inside your own NetBird network. Unlike SSO or password, there is no login page — the proxy verifies the client through its WireGuard tunnel before serving any traffic. Clients that are not on a NetBird peer in your account cannot reach the service at all.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/authentication/auth-netbird-only-modal.png" alt="NetBird-Only Access configuration modal with access group selection" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. The proxy receives an inbound HTTP request and resolves the source address back to a NetBird peer using its embedded `netbird proxy` client. Requests with no peer-of-origin are rejected.
|
||||
2. The owning user's groups are checked against the service's **access groups**. If the user is not in any of them, the request is rejected with `403`.
|
||||
3. The request is forwarded to the backend with two extra headers identifying the caller — see [Identity headers stamped on upstream requests](#identity-headers-stamped-on-upstream-requests).
|
||||
|
||||
By default the proxy reaches the backend over the encrypted WireGuard tunnel through a NetBird peer — the service is reachable only from inside your NetBird network, and access is gated by group membership:
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/authentication/netbird-only-via-peer-diagram.png" alt="Diagram of a NetBird-Only service: the device tunnels to the proxy cluster, the management service checks group membership, and requests from allowed users are forwarded over WireGuard through a NetBird peer to the backend service while others get a 403" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
For services that target a **Proxy Cluster** (or have **Direct Upstream** enabled), the proxy dials the backend directly from its own host network stack instead of through a peer — see [Private services](/manage/reverse-proxy/bring-your-own-proxy#private-services-net-bird-only-access).
|
||||
|
||||
**Access groups:**
|
||||
|
||||
When you enable NetBird-Only Access you must pick at least one **access group**. Only peers whose owning user (or the peer itself, for user-less peers like cluster proxies) is in one of those groups can reach the service. The service-save button stays disabled until you pick a group.
|
||||
|
||||
**Cluster capability requirement:**
|
||||
|
||||
NetBird-Only Access is only available on clusters that report the `Private` capability — that is, clusters where at least one connected proxy runs embedded in a NetBird client (`netbird proxy`) and serves over a WireGuard tunnel. The toggle on the **Authentication** tab is grey when the selected base domain belongs to a cluster without that capability, with a tooltip explaining the requirement.
|
||||
|
||||
NetBird Cloud's shared clusters do not currently advertise the `Private` capability. To use NetBird-Only Access:
|
||||
|
||||
- **NetBird Cloud:** run your own [account cluster](/manage/reverse-proxy/bring-your-own-proxy). The BYOP proxy joins your mesh as an embedded peer and gives the cluster the `Private` capability automatically.
|
||||
- **Self-hosted:** deploy at least one proxy instance in embedded mode (`netbird proxy`). See the [BYOP guide](/manage/reverse-proxy/bring-your-own-proxy) — the same setup applies to a management-wide proxy.
|
||||
|
||||
**Default access-control baseline:**
|
||||
|
||||
Enabling NetBird-Only Access applies an implicit allow rule for the NetBird network range on the **Access Control** tab — additional CIDR rules you add are layered on top of that baseline. Country and CrowdSec checks are skipped on the overlay path because the source address is always a NetBird CGNAT address with no meaningful geo or reputation data.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-access-control-modal.png" alt="Access Control tab on a NetBird-only service, showing the default-allow callout" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
**Identity headers stamped on upstream requests:**
|
||||
|
||||
When a request is forwarded to the backend, the proxy injects two headers identifying the authenticated caller:
|
||||
|
||||
| Header | Value |
|
||||
|--------|-------|
|
||||
| `X-NetBird-User` | Display identity of the calling user — email when the peer is attached to a user, peer name otherwise |
|
||||
| `X-NetBird-Groups` | Comma-separated list of group display names the user belongs to. Falls back to group IDs at positions where the display name was unavailable at session-mint time |
|
||||
|
||||
Any client-supplied `X-NetBird-User` or `X-NetBird-Groups` headers are **stripped** from the inbound request before the proxy stamps its own — clients cannot impersonate a user by setting the header. Backends can read these headers safely and use them to drive per-user authorization, logging, or personalization. See [Backend Service Configuration](/manage/reverse-proxy/service-configuration#netbird-identity-headers) for example backend integrations.
|
||||
|
||||
**Best for:** internal tools that should only be reachable from a company-managed device, admin consoles, dashboards, dev/staging endpoints, and any service where you want the WireGuard tunnel to be the trust boundary instead of an operator-managed password or IdP.
|
||||
|
||||
### SSO (Single Sign-On)
|
||||
|
||||
SSO authentication requires users to authenticate through your identity provider (IdP) using OIDC before they can access the service. When a user visits the service URL, they are redirected to your IdP login page. After successful authentication, they are granted access to the service.
|
||||
@@ -115,7 +176,7 @@ Services can also be configured without any authentication. When no authenticati
|
||||
|
||||
## Combining authentication methods
|
||||
|
||||
You can enable multiple authentication methods on a single service simultaneously. When more than one method is active, users can authenticate using **any** of the enabled methods - they choose which one to use when accessing the service.
|
||||
You can enable multiple **operator auth methods** on a single service simultaneously. When more than one is active, users authenticate using **any** of the enabled methods — they choose which one to use when accessing the service.
|
||||
|
||||
For example, you could enable both **SSO** and **Password** on the same service. Team members who have accounts in your identity provider can authenticate with SSO, while external partners or contractors can use a shared password. This gives you flexibility without requiring everyone to be in your IdP.
|
||||
|
||||
@@ -127,7 +188,11 @@ Common combinations include:
|
||||
| **SSO + Header Auth** | Team members authenticate in a browser; automated systems use an API key |
|
||||
| **SSO + PIN Code** | Team members use SSO; quick access via PIN for specific scenarios |
|
||||
| **Password + PIN Code** | Different shared credentials for different groups of users |
|
||||
| **Any auth + Access Restrictions** | IP/country restrictions as a first layer, then authentication for identity |
|
||||
| **Any operator auth + Access Restrictions** | IP/country restrictions as a first layer, then authentication for identity |
|
||||
|
||||
<Note>
|
||||
**NetBird-Only Access does not combine with operator auth on the same service.** It is the protection mechanism for a private service — the WireGuard tunnel is the trust boundary. If you need a single backend reachable both privately (mesh peers) and publicly (with operator auth), expose it as two services on different subdomains.
|
||||
</Note>
|
||||
|
||||
## Access restrictions
|
||||
|
||||
@@ -213,9 +278,20 @@ Authentication and access control are configured in separate tabs of the service
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-access-control-modal.png" alt="Authentication tab showing all available authentication methods" className="imagewrapper"/>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-access-control-modal.png" alt="Access Control tab on a service, showing the rule list and the NetBird-only baseline callout" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
### Setting up NetBird-Only Access (private services)
|
||||
|
||||
1. Open the service modal (create or edit).
|
||||
2. Confirm the selected base domain is on a cluster that reports the **Private** capability — the **NetBird-Only Access** row in the next step is greyed out otherwise. See [Cluster capability requirement](#netbird-only-access-private-services) above for how to enable it on your cluster.
|
||||
3. Switch to the **Authentication** tab.
|
||||
4. Click **NetBird-Only Access**.
|
||||
5. In the modal, pick one or more **access groups**. Only peers whose owning user is in one of these groups can reach the service. The **Enable** button stays disabled until at least one group is selected.
|
||||
6. Click **Enable**, then **Save Changes** on the service.
|
||||
|
||||
To remove NetBird-Only Access, reopen the modal and click **Remove**. The service immediately reverts to the operator-auth flow (defaulting to no auth) — re-enable SSO, password, PIN, or header auth as needed before saving.
|
||||
|
||||
### Setting up SSO
|
||||
|
||||
1. Open the service modal (create or edit).
|
||||
|
||||
@@ -41,7 +41,14 @@ NetBird recognises two cluster types, distinguished by the `type` field on the `
|
||||
| **Visible to other accounts** | Yes, as an available cluster in their service-creation flow | No — only the owning account sees it |
|
||||
| **Delete from dashboard** | Not allowed | Allowed (account owner only) |
|
||||
|
||||
Both cluster types appear together on the **Clusters** page. The **Type** badge next to the cluster name marks each row as **shared** or **account**, the **Status** column shows whether at least one proxy in the cluster has heartbeated within the last two minutes, and the **Features** column lists the capabilities reported by the connected proxies (custom-port L4 support, subdomain requirement, CrowdSec IP-reputation enforcement).
|
||||
Both cluster types appear together on the **Clusters** page. The **Type** badge next to the cluster name marks each row as **shared** or **account**, the **Status** column shows whether at least one proxy in the cluster has heartbeated within the last two minutes, and the **Features** column lists the capabilities reported by the connected proxies:
|
||||
|
||||
| Feature badge | Meaning |
|
||||
|---------------|---------|
|
||||
| **Custom Ports** | The cluster can bind arbitrary TCP/UDP listen ports for L4 services. |
|
||||
| **Subdomain Required** | Services on this cluster must use a subdomain — the bare cluster apex is not addressable. |
|
||||
| **CrowdSec** | The cluster has CrowdSec IP-reputation configured across all active proxies. |
|
||||
| **Private** | The cluster can publish services that are only reachable from peers in your NetBird network. Required to enable [NetBird-Only Access](/manage/reverse-proxy/authentication#netbird-only-access-private-services) and the **Proxy Cluster** target type on services. Activated when at least one connected proxy in the cluster runs as an embedded NetBird peer (`netbird proxy`). |
|
||||
|
||||
When creating a service you pick a base domain from any cluster you can reach: shared clusters are always available; account clusters appear only for the account that owns them. There is no functional difference at the data-plane — services on either cluster type behave identically once a request lands. The choice is operational: shared clusters are zero-effort, account clusters give you control over location, TLS, and the data path.
|
||||
|
||||
@@ -194,6 +201,33 @@ Once the cluster is connected, your BYOP domain shows up in the service creation
|
||||
|
||||
Traffic to `subdomain.proxy.company.com` is now received by your BYOP proxy, terminated locally with a Let's Encrypt certificate, and forwarded over WireGuard to the target peer or network resource.
|
||||
|
||||
## Private services (NetBird-Only Access)
|
||||
|
||||
A BYOP cluster whose proxy runs embedded as a NetBird peer (`netbird proxy` mode — the default for the `netbirdio/reverse-proxy` image) reports the `Private` capability if started with the flag `--private` or environment variable `NB_PROXY_PRIVATE=true`. With that capability set, the cluster unlocks two new options anywhere it is selected:
|
||||
|
||||
- **NetBird-Only Access** on the service's **Authentication** tab — turn the service into a *private service* that only peers in your NetBird network can reach. See [NetBird-Only Access](/manage/reverse-proxy/authentication#net-bird-only-access-private-services) for the full behaviour, identity-header semantics, and access-group rules.
|
||||
- **Proxy Cluster** in the target picker — point the service at a hostname or IP that the embedded proxy can resolve directly from its own host stack (without WireGuard), with **Direct Upstream** locked on. Useful when the upstream is co-located with the BYOP proxy and you do not need (or want) to route it through the mesh.
|
||||
|
||||
With a **Proxy Cluster** target (or **Direct Upstream** enabled on a peer/resource target), the service is still reachable only over the NetBird tunnel and still gated by group membership, but the proxy reaches the upstream directly via its host network stack — no WireGuard peer is required between the proxy and the backend:
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/byop/netbird-only-direct-upstream-diagram.png" alt="Diagram of a NetBird-Only service with Direct Upstream: the device tunnels to the proxy cluster, the management service checks group membership, and the proxy reaches the backend service directly over the host network stack with no WireGuard peer" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
NetBird Cloud's shared clusters do not currently advertise `Private`. Running your own BYOP cluster is the supported way to enable private services for an account on Cloud. For self-hosted, the same applies — the proxy must be running with the flag set.
|
||||
|
||||
When the selected base domain does *not* advertise the `Private` capability:
|
||||
|
||||
- The **NetBird-Only Access** row on the Authentication tab is greyed out, with a tooltip explaining the requirement.
|
||||
- The **Proxy Cluster** option is hidden from the target picker.
|
||||
- **Direct Upstream** is locked off in service settings.
|
||||
|
||||
To verify the capability is set, check the cluster row on the **Clusters** page — a **Private** badge appears in the Features column when at least one connected proxy is running in embedded mode.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/byop/byop-clusters-private-feature.png" alt="Clusters page row showing the Private feature badge in the Features column" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
## High availability
|
||||
|
||||
Run multiple proxy replicas with the **same** `NB_PROXY_TOKEN` and **same** `NB_PROXY_DOMAIN` to form an HA cluster within your account. Each replica:
|
||||
@@ -264,7 +298,7 @@ docker run -d \
|
||||
|
||||
### Manage clusters
|
||||
|
||||
The **Clusters** page lists each cluster reachable from your account, its **Online** status, the count of currently connected proxies, and the feature flags (custom ports, subdomain requirement, CrowdSec) reported by its proxies. The same data is available via `GET /api/reverse-proxies/clusters` — each entry carries a `type` field (`"account"` for BYOP clusters you own, `"shared"` for platform-managed clusters). The **Delete** action is only available on account clusters. From the page you can:
|
||||
The **Clusters** page lists each cluster reachable from your account, its **Online** status, the count of currently connected proxies, and the feature flags (custom ports, subdomain requirement, CrowdSec, private) reported by its proxies. The same data is available via `GET /api/reverse-proxies/clusters` — each entry carries a `type` field (`"account"` for BYOP clusters you own, `"shared"` for platform-managed clusters). The **Delete** action is only available on account clusters. From the page you can:
|
||||
|
||||
- **Refresh** to pull fresh status.
|
||||
- **Delete** an account cluster — this removes the cluster's database record and hides it from the API and dashboard. The same is exposed as `DELETE /api/reverse-proxies/clusters/{clusterAddress}`. Note that any proxy process still running with the cluster's token keeps its gRPC stream open until you stop it or revoke the token. To fully tear down an account cluster, delete it *and* either stop the proxy container or revoke its token.
|
||||
|
||||
@@ -73,6 +73,7 @@ A target defines where proxied traffic is sent within your NetBird network. Ever
|
||||
| **Host** | A network resource identified by an IP address | Select from your network resources |
|
||||
| **Domain** | A network resource identified by a domain name | Select from your network resources |
|
||||
| **Subnet** | A network resource within a CIDR range | Select from your network resources, then specify an IP within the range |
|
||||
| **Proxy Cluster** | An upstream reached directly via the host network of the cluster's embedded NetBird proxy. Only available on clusters that report the `Private` capability. | Select the cluster from the picker, then enter a hostname or IP that the embedded proxy can resolve from its own host stack. |
|
||||
|
||||
Target properties vary by service mode:
|
||||
|
||||
@@ -125,12 +126,17 @@ You can protect a service with one or more authentication methods. When multiple
|
||||
|
||||
| Method | HTTP services | L4 services | Description |
|
||||
|--------|:---:|:---:|-------------|
|
||||
| **NetBird-Only Access** | Yes | No | Restrict the service to peers in your own NetBird network. The proxy validates the request against your WireGuard tunnel and only allows in connections from peers that belong to the configured access groups. Available on clusters that advertise the `Private` capability. |
|
||||
| **SSO (Single Sign-On)** | Yes | No | Authenticate via your identity provider using OIDC. Optionally restrict access to specific user groups. |
|
||||
| **Password** | Yes | No | Protect with a shared password. |
|
||||
| **PIN Code** | Yes | No | Protect with a numeric PIN code. |
|
||||
| **Header Authentication** | Yes | No | Validate a static header value (API key, Bearer token, Basic auth). Useful for programmatic access. |
|
||||
| **Access Restrictions** | Yes | Yes | Restrict access by IP CIDR range, country, or CrowdSec IP reputation. Works at the connection level, so it applies to all service modes. |
|
||||
|
||||
<Note>
|
||||
**NetBird-Only Access** turns the service into a *private service*: it replaces the operator-managed auth methods (SSO, password, PIN, header) on the same service. Use it when you want a service exposed only inside your NetBird mesh; combine the operator auth methods with each other when you want a service exposed publicly.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
If you save a service with no authentication or access restrictions configured, the dashboard will display a warning. Public services are accessible to anyone on the internet who knows the URL.
|
||||
</Note>
|
||||
@@ -242,11 +248,11 @@ In the **Details** tab:
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-service-details.png" alt="Add Service modal showing the Details tab" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
6. In the target configuration, select the **type** (Peer, Host, Domain, or Subnet), then choose the specific peer or resource.
|
||||
7. For HTTP services, set the **protocol** (HTTP or HTTPS) and **port** for the target. Optionally, enter a **path** for path-based routing. For L4 services, set the target **host/IP** and **port**.
|
||||
6. In the target configuration, select the **type** (Peer, Host, Domain, Subnet, or Proxy Cluster), then choose the specific peer, resource, or cluster.
|
||||
7. For HTTP services, set the **protocol** (HTTP or HTTPS) and **port** for the target. Optionally, enter a **path** for path-based routing. For L4 services, set the target **host/IP** and **port**. For **Proxy Cluster** targets, the host field accepts any hostname or IP the cluster's embedded proxy can resolve from its own host stack — see [Private services](/manage/reverse-proxy/bring-your-own-proxy#private-services-net-bird-only-access) for details.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-target.png" alt="Add Target configuration modal" className="imagewrapper"/>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-target.png" alt="Add Target configuration modal showing the unified Peer / Resource / Proxy Cluster picker" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
You can add multiple targets. HTTP services support path-based routing across targets.
|
||||
@@ -259,6 +265,7 @@ Switch to the **Authentication** tab to configure how users are authenticated be
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-service-auth.png" alt="Add Service modal showing the Authentication tab" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
- Enable **NetBird-Only Access** to make the service reachable only from peers in the selected NetBird groups (private service). Only appears when the selected base domain is on a cluster that advertises the `Private` capability. Picking this method hides the operator auth options below — the two modes are mutually exclusive.
|
||||
- Enable **SSO** to require users to authenticate through your identity provider. Optionally restrict access to specific groups.
|
||||
- Enable **Password** and set a shared password.
|
||||
- Enable **PIN Code** and set a numeric code.
|
||||
@@ -266,7 +273,7 @@ Switch to the **Authentication** tab to configure how users are authenticated be
|
||||
- Leave all methods disabled for public (unauthenticated) access.
|
||||
|
||||
<Note>
|
||||
You can enable multiple authentication methods simultaneously. Users will be able to choose their preferred method when accessing the service.
|
||||
You can enable multiple operator auth methods (SSO, password, PIN, header) simultaneously — users pick one to authenticate with. NetBird-Only Access is a different mode and replaces the operator auth set on that service.
|
||||
</Note>
|
||||
|
||||
### Step 3b: Configure access control
|
||||
@@ -279,6 +286,10 @@ Switch to the **Access Control** tab to restrict access by IP address, country,
|
||||
|
||||
Access restrictions are evaluated before authentication: if a connection is blocked by an access restriction rule, it is rejected before any authentication check.
|
||||
|
||||
<Note>
|
||||
**NetBird-Only services:** when [NetBird-Only Access](/manage/reverse-proxy/authentication#netbird-only-access-private-services) is enabled on a service, an allow rule for the NetBird network range is applied automatically. Any rules you add on this tab are layered on top of that baseline — country and CrowdSec checks are skipped on the overlay path because the source address is always a NetBird CGNAT address.
|
||||
</Note>
|
||||
|
||||
### Step 4: Configure advanced settings
|
||||
|
||||
Switch to the **Settings** tab to adjust advanced proxy behavior. The available settings depend on the service mode.
|
||||
@@ -287,9 +298,16 @@ Switch to the **Settings** tab to adjust advanced proxy behavior. The available
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-service-settings.png" alt="Add Service modal showing the Settings tab" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
The per-service options differ between HTTP and L4 (TCP/UDP/TLS) services and apply at different points along the request path:
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-service-options-diagram.png" alt="Diagram showing per-service options: HTTP services (Pass Host Header, Rewrite Redirects) and L4 services (PROXY Protocol v2, Session Idle Timeout) and where each applies between the user, proxy service, and backend" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
**HTTP services:**
|
||||
- **Pass Host Header** - when enabled, the original `Host` header from the client request is forwarded to the backend service instead of the target's hostname. This is useful when the backend application needs to know the public domain it is being accessed through.
|
||||
- **Rewrite Redirects** - when enabled, `Location` headers in backend responses (used for HTTP redirects) are rewritten to use the public domain. This prevents users from being redirected to internal URLs that they cannot reach.
|
||||
- **Direct Upstream** *(NetBird-Only services only)* - dial the upstream from the proxy host's network stack instead of through the WireGuard tunnel. Off by default for **Peer** and **Resource** targets; locked **on** for **Proxy Cluster** targets because the cluster has no WireGuard endpoint to fall back to. Turn it on for peer/resource targets when the upstream is reachable from the proxy host without WireGuard (e.g., a sidecar on the same machine).
|
||||
|
||||
**L4 services (TCP, UDP, TLS):**
|
||||
- **PROXY Protocol** (TCP/TLS only) - when enabled, the proxy sends a PROXY Protocol v2 header to the backend, allowing it to see the real client IP address. The backend must support PROXY Protocol to use this option.
|
||||
|
||||
@@ -102,6 +102,43 @@ If you're running NextCloud AIO this should be configured automatically during s
|
||||
|
||||
Nextcloud supports CIDR notation for IPv4 ranges. When a request arrives from a trusted proxy, Nextcloud reads the real client IP from the `X-Forwarded-For` header instead of using the proxy's IP.
|
||||
|
||||
## NetBird identity headers
|
||||
|
||||
Services configured with [NetBird-Only Access](/manage/reverse-proxy/authentication#netbird-only-access-private-services) are private — every inbound request is authenticated against the WireGuard tunnel before it reaches your backend. The proxy attaches two headers to each upstream request identifying the caller:
|
||||
|
||||
| Header | Value |
|
||||
|--------|-------|
|
||||
| `X-NetBird-User` | The calling user's email (or peer name when the peer has no user owner). |
|
||||
| `X-NetBird-Groups` | Comma-separated list of the user's group display names. Falls back to group IDs at positions where the display name was unavailable at session-mint time. |
|
||||
|
||||
Use these headers in your backend to drive per-user authorization, audit logging, or personalization without running your own login flow. Because the proxy has already verified the caller's WireGuard identity, the headers are trustworthy for any backend that sits behind a NetBird-Only service.
|
||||
|
||||
<Warning>
|
||||
**Anti-spoof discipline.** The proxy strips any client-supplied `X-NetBird-User` or `X-NetBird-Groups` headers from the inbound request before stamping its own values. Your backend should still verify it is reachable only through a NetBird-Only service — anything that bypasses the proxy (e.g., direct connections from inside your Docker network) will reach the backend without these headers, and your code should treat their absence as "unauthenticated."
|
||||
</Warning>
|
||||
|
||||
### Example: read the user in a backend
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI, Header, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@app.get("/me")
|
||||
def me(
|
||||
user: str | None = Header(default=None, alias="X-NetBird-User"),
|
||||
groups: str | None = Header(default=None, alias="X-NetBird-Groups"),
|
||||
):
|
||||
if user is None:
|
||||
raise HTTPException(403, "must be accessed through a NetBird private service")
|
||||
return {
|
||||
"user": user,
|
||||
"groups": groups.split(",") if groups else [],
|
||||
}
|
||||
```
|
||||
|
||||
The same pattern works in any backend framework — read the two headers, refuse the request if `X-NetBird-User` is absent, and use the groups for per-user authorization decisions.
|
||||
|
||||
## Verifying your configuration
|
||||
|
||||
After updating your backend's trusted proxy settings:
|
||||
|
||||
@@ -95,6 +95,7 @@ All reverse proxy configurations for the combined container must route the follo
|
||||
| `/ws-proxy/management*` | WebSocket | netbird-server:80 | WebSocket upgrade required |
|
||||
| `/signalexchange.SignalExchange/*` | gRPC | netbird-server:80 | HTTP/2 (h2c) required |
|
||||
| `/management.ManagementService/*` | gRPC | netbird-server:80 | HTTP/2 (h2c) required |
|
||||
| `/management.ProxyService/*` | gRPC | netbird-server:80 | HTTP/2 (h2c) required. Only needed if using the [Reverse Proxy feature](/manage/reverse-proxy). |
|
||||
| `/api/*` | HTTP | netbird-server:80 | REST API |
|
||||
| `/oauth2/*` | HTTP | netbird-server:80 | Embedded IdP |
|
||||
| `/*` | HTTP | dashboard:80 | Catch-all for dashboard |
|
||||
@@ -175,7 +176,7 @@ services:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
# gRPC router (needs h2c backend for HTTP/2 cleartext)
|
||||
- traefik.http.routers.netbird-grpc.rule=Host(`netbird.example.com`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`))
|
||||
- traefik.http.routers.netbird-grpc.rule=Host(`netbird.example.com`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))
|
||||
- traefik.http.routers.netbird-grpc.entrypoints=websecure
|
||||
- traefik.http.routers.netbird-grpc.tls=true
|
||||
- traefik.http.routers.netbird-grpc.tls.certresolver=letsencrypt
|
||||
@@ -262,7 +263,7 @@ server {
|
||||
}
|
||||
|
||||
# Native gRPC (signal + management)
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.(ManagementService|ProxyService))/ {
|
||||
grpc_pass grpc://netbird_server;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
@@ -335,7 +336,7 @@ server {
|
||||
}
|
||||
|
||||
# Native gRPC (signal + management)
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.(ManagementService|ProxyService))/ {
|
||||
grpc_pass grpc://netbird_server;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
@@ -440,7 +441,7 @@ location ~ ^/(relay|ws-proxy/) {
|
||||
}
|
||||
|
||||
# Native gRPC (signal + management)
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.(ManagementService|ProxyService))/ {
|
||||
grpc_pass grpc://netbird-server:80;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
@@ -490,7 +491,7 @@ location ~ ^/(relay|ws-proxy/) {
|
||||
}
|
||||
|
||||
# Native gRPC (signal + management)
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.ManagementService)/ {
|
||||
location ~ ^/(signalexchange\.SignalExchange|management\.(ManagementService|ProxyService))/ {
|
||||
grpc_pass grpc://127.0.0.1:8081;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
@@ -876,6 +877,14 @@ server {
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# Proxy gRPC (only needed if using the Reverse Proxy feature)
|
||||
location /management.ProxyService/ {
|
||||
grpc_pass grpc://netbird_management;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# Embedded IdP OAuth2
|
||||
location /oauth2/ {
|
||||
proxy_pass http://netbird_management;
|
||||
@@ -994,6 +1003,14 @@ server {
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# Proxy gRPC (only needed if using the Reverse Proxy feature)
|
||||
location /management.ProxyService/ {
|
||||
grpc_pass grpc://netbird_management;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# Embedded IdP OAuth2
|
||||
location /oauth2/ {
|
||||
proxy_pass http://netbird_management;
|
||||
@@ -1153,6 +1170,9 @@ netbird.example.com {
|
||||
# Management gRPC
|
||||
reverse_proxy /management.ManagementService/* h2c://netbird-management:80
|
||||
|
||||
# Proxy gRPC (only needed if using the Reverse Proxy feature)
|
||||
reverse_proxy /management.ProxyService/* h2c://netbird-management:80
|
||||
|
||||
# Embedded IdP OAuth2
|
||||
reverse_proxy /oauth2/* netbird-management:80
|
||||
|
||||
@@ -1185,6 +1205,9 @@ netbird.example.com {
|
||||
# Management gRPC
|
||||
reverse_proxy /management.ManagementService/* h2c://127.0.0.1:8081
|
||||
|
||||
# Proxy gRPC (only needed if using the Reverse Proxy feature)
|
||||
reverse_proxy /management.ProxyService/* h2c://127.0.0.1:8081
|
||||
|
||||
# Embedded IdP OAuth2
|
||||
reverse_proxy /oauth2/* 127.0.0.1:8081
|
||||
|
||||
@@ -1302,6 +1325,14 @@ location /management.ManagementService/ {
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# gRPC for Proxy service (only needed if using the Reverse Proxy feature)
|
||||
location /management.ProxyService/ {
|
||||
grpc_pass grpc://netbird-management:80;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
##### NPM running on host (Multi-Container)
|
||||
@@ -1398,6 +1429,14 @@ location /management.ManagementService/ {
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
# gRPC for Proxy service (only needed if using the Reverse Proxy feature)
|
||||
location /management.ProxyService/ {
|
||||
grpc_pass grpc://127.0.0.1:8081;
|
||||
grpc_read_timeout 1d;
|
||||
grpc_send_timeout 1d;
|
||||
grpc_socket_keepalive on;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -572,20 +572,87 @@ If your self-hosted deployment currently uses Nginx, Caddy, or another reverse p
|
||||
|
||||
## Environment variable reference
|
||||
|
||||
The proxy is configured entirely through environment variables (each one maps to an equivalent CLI flag). The tables below cover every available option grouped by purpose. Only `NB_PROXY_TOKEN` and `NB_PROXY_DOMAIN` are required; the rest have sensible defaults.
|
||||
|
||||
### Core
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `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. | - |
|
||||
| `NB_PROXY_DOMAIN` | Yes | Base domain for this proxy instance (e.g., `proxy.example.com`or `netbird.example.com`). Determines the domain available for services. | - |
|
||||
| `NB_PROXY_DOMAIN` | Yes | Base domain for this proxy instance (e.g., `proxy.example.com` or `netbird.example.com`). Determines the domain available for services. | - |
|
||||
| `NB_PROXY_MANAGEMENT_ADDRESS` | No | URL of your NetBird management server. The proxy connects via gRPC to register itself. | `https://api.netbird.io:443` |
|
||||
| `NB_PROXY_ADDRESS` | No | Address the proxy listens on. | `:8443` (Docker), `:443` (binary) |
|
||||
| `NB_PROXY_ALLOW_INSECURE` | No | Allow an insecure (non-TLS) gRPC connection to the management server. Set to `true` only when connecting over an internal Docker network; it is a no-op for `https://` management addresses. | `false` |
|
||||
| `NB_PROXY_LOG_LEVEL` | No | Log level: `panic`, `fatal`, `error`, `warn`, `info`, `debug`, or `trace`. | `info` |
|
||||
| `NB_PROXY_DEBUG_LOGS` | No | Enable debug-level logging. **Deprecated** - use `NB_PROXY_LOG_LEVEL=debug` instead. | `false` |
|
||||
|
||||
### TLS certificates
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_CERTIFICATE_DIRECTORY` | No | Directory where certificate files are stored (and where ACME-provisioned certificates are written). | `./certs` |
|
||||
| `NB_PROXY_CERTIFICATE_FILE` | No | TLS certificate filename within the certificate directory (static certificate mode). | `tls.crt` |
|
||||
| `NB_PROXY_CERTIFICATE_KEY_FILE` | No | TLS private key filename within the certificate directory (static certificate mode). | `tls.key` |
|
||||
| `NB_PROXY_WILDCARD_CERT_DIR` | No | Directory containing wildcard certificate pairs (`<name>.crt`/`<name>.key`). Wildcard patterns are extracted from the certificate SANs automatically. | - |
|
||||
| `NB_PROXY_CERT_LOCK_METHOD` | No | Certificate lock method for coordinating multiple replicas: `auto`, `flock`, or `k8s-lease`. | `auto` |
|
||||
|
||||
### ACME (automatic certificates)
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_ACME_CERTIFICATES` | No | Set to `true` to enable automatic TLS certificate provisioning via Let's Encrypt. | `false` |
|
||||
| `NB_PROXY_ACME_CHALLENGE_TYPE` | No | ACME challenge type: `tls-alpn-01` (port 443) or `http-01` (port 80). | `tls-alpn-01` |
|
||||
| `NB_PROXY_CERTIFICATE_FILE` | No | TLS certificate filename within the certificate directory (for static certificate mode). | `tls.crt` |
|
||||
| `NB_PROXY_CERTIFICATE_KEY_FILE` | No | TLS private key filename within the certificate directory (for static certificate mode). | `tls.key` |
|
||||
| `NB_PROXY_CERTIFICATE_DIRECTORY` | No | Directory where static certificate files are stored. | `./certs` |
|
||||
| `NB_PROXY_ALLOW_INSECURE` | No | Allow insecure (non-TLS) gRPC connection to the management server. Set to `true` when connecting over an internal Docker network. | `false` |
|
||||
| `NB_PROXY_FORWARDED_PROTO` | No | Protocol to report in the `X-Forwarded-Proto` header. Set to `https` when TLS is terminated at the proxy. | - |
|
||||
| `NB_PROXY_DEBUG_LOGS` | No | Enable debug-level logging. | `false` |
|
||||
| `NB_PROXY_ACME_CHALLENGE_TYPE` | No | ACME challenge type: `tls-alpn-01` (port 443) or `http-01` (requires port 80). | `tls-alpn-01` |
|
||||
| `NB_PROXY_ACME_ADDRESS` | No | HTTP address for ACME `http-01` challenges. Only used when the challenge type is `http-01`. | `:80` |
|
||||
| `NB_PROXY_ACME_DIRECTORY` | No | ACME directory URL. Override to use a CA other than Let's Encrypt. | Let's Encrypt production |
|
||||
| `NB_PROXY_ACME_EAB_KID` | No | ACME External Account Binding key ID, for CAs that require EAB registration. | - |
|
||||
| `NB_PROXY_ACME_EAB_HMAC_KEY` | No | ACME External Account Binding HMAC key, for CAs that require EAB registration. | - |
|
||||
|
||||
### Networking and forwarding
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_FORWARDED_PROTO` | No | Value to report in the `X-Forwarded-Proto` header for backends: `auto`, `http`, or `https`. | `auto` |
|
||||
| `NB_PROXY_TRUSTED_PROXIES` | No | Comma-separated list of trusted upstream proxy CIDR ranges (e.g. `10.0.0.0/8,192.168.1.1`) used when parsing forwarded client IPs. | - |
|
||||
| `NB_PROXY_PROXY_PROTOCOL` | No | Enable PROXY protocol on TCP listeners to preserve client IPs behind L4 proxies. | `false` |
|
||||
| `NB_PROXY_WG_PORT` | No | WireGuard listen port (`0` = random). A fixed port only works with single-account deployments. | `0` |
|
||||
| `NB_PROXY_PRESHARED_KEY` | No | Pre-shared key for the tunnel between the proxy and peers. | - |
|
||||
| `NB_PROXY_SUPPORTS_CUSTOM_PORTS` | No | Whether the proxy can bind arbitrary ports for UDP/TCP passthrough. | `true` |
|
||||
| `NB_PROXY_REQUIRE_SUBDOMAIN` | No | Require a subdomain label in front of the cluster domain. | `false` |
|
||||
| `NB_PROXY_PRIVATE` | No | Serve private services with NetBird-Only authentication, reachable exclusively over the WireGuard tunnel (also enables per-account inbound listeners). Advanced; intended for proxies embedded in a NetBird client rather than standalone deployments. | `false` |
|
||||
| `NB_PROXY_MAX_DIAL_TIMEOUT` | No | Cap the per-service backend dial timeout (`0` = no cap), e.g. `10s`. | `0` |
|
||||
| `NB_PROXY_MAX_SESSION_IDLE_TIMEOUT` | No | Cap the per-service session idle timeout (`0` = no cap), e.g. `5m`. | `0` |
|
||||
|
||||
### Observability and health
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_HEALTH_ADDRESS` | No | Address for the health probe endpoint (liveness/readiness/startup). | `localhost:8080` |
|
||||
| `NB_PROXY_DEBUG_ENDPOINT` | No | Enable the debug HTTP endpoint. | `false` |
|
||||
| `NB_PROXY_DEBUG_ENDPOINT_ADDRESS` | No | Address for the debug HTTP endpoint. | `localhost:8444` |
|
||||
|
||||
### IP reputation (CrowdSec)
|
||||
|
||||
See [Step 7: Enable CrowdSec IP reputation](#step-7-optional-enable-crowdsec-ip-reputation) for the full setup.
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_CROWDSEC_API_URL` | No | CrowdSec LAPI URL for IP reputation checks (e.g. `http://crowdsec:8080`). Empty disables CrowdSec. | - |
|
||||
| `NB_PROXY_CROWDSEC_API_KEY` | No | CrowdSec bouncer API key generated by `cscli bouncers add`. | - |
|
||||
|
||||
### Geolocation
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_GEO_DATA_DIR` | No | Directory for the GeoLite2 MMDB file, used for geo-based access rules (auto-downloaded if missing). | `/var/lib/netbird/geolocation` |
|
||||
|
||||
### Advanced tunnel tuning
|
||||
|
||||
These rarely need changing; leave them unset unless you are tuning throughput.
|
||||
|
||||
| Variable | Required | Description | Default |
|
||||
|----------|----------|-------------|---------|
|
||||
| `NB_PROXY_PREALLOCATED_BUFFERS` | No | Cap the per-tunnel buffer pool (`0` = uncapped upstream default). Setting it below the eager-allocation floor can deadlock startup. | `0` |
|
||||
| `NB_PROXY_MAX_BATCH_SIZE` | No | Override the per-tunnel batch size, controlling how many buffers each receive/TUN worker eagerly allocates (`0` = platform default). | `0` |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||