diff --git a/src/pages/manage/reverse-proxy/access-logs.mdx b/src/pages/manage/reverse-proxy/access-logs.mdx index c3a7b667..a972ac2d 100644 --- a/src/pages/manage/reverse-proxy/access-logs.mdx +++ b/src/pages/manage/reverse-proxy/access-logs.mdx @@ -1,15 +1,15 @@ import {Note} from "@/components/mdx" export const description = - 'Monitor and audit HTTP requests flowing through your NetBird reverse proxy services with detailed access logs.' + 'Monitor and audit HTTP requests and L4 connections flowing through your NetBird reverse proxy services with detailed access logs.' # Reverse Proxy Access Logs -NetBird logs every request that passes through your reverse proxy services. Access logs provide visibility into who is accessing your services, from where, and whether requests were allowed or denied. This is useful for auditing, debugging, and monitoring traffic to your publicly exposed services. +NetBird logs every request and connection that passes through your reverse proxy services, including both HTTP and L4 (TCP, UDP, TLS) traffic. Access logs provide visibility into who is accessing your services, from where, and whether requests were allowed or denied. This is useful for auditing, debugging, and monitoring traffic to your publicly exposed services. ## Viewing access logs -Access logs are available in the NetBird dashboard under **Activity** > **Proxy Events**. This view displays a table of all HTTP requests that have passed through your reverse proxy services, with filters to narrow down results by time range, status, or other fields. +Access logs are available in the NetBird dashboard under **Activity** > **Proxy Events**. This view displays a table of all HTTP requests and L4 connections that have passed through your reverse proxy services, with filters to narrow down results by time range, status, or other fields.

Proxy Events table showing reverse proxy access log entries @@ -23,30 +23,49 @@ GET /api/events/proxy ## What access logs capture -Each log entry records the following information about an HTTP request: - -| Field | Description | -|-------|-------------| -| **Timestamp** | When the request occurred | -| **Method** | HTTP method (GET, POST, PUT, DELETE, etc.) | -| **Host** | The domain the request was made to | -| **Path** | The URL path requested | -| **Status Code** | HTTP status code returned (200, 401, 403, 500, etc.) | -| **Duration** | How long the request took (in milliseconds) | -| **Source IP** | The client's IP address | -| **Auth Method** | Which authentication method was used (SSO, password, PIN, or none) | -| **User ID** | The authenticated user's ID (if SSO was used) | -| **Country** | Country of origin based on source IP geolocation | -| **City** | City of origin based on source IP geolocation | -| **Reason** | Reason for denial (if applicable) | +Every log entry (HTTP and L4) shares a common set of fields. Some fields are only meaningful for certain protocols. + +| Field | Description | HTTP | L4 (TCP/UDP/TLS) | +|-------|-------------|:----:|:-----------------:| +| **Timestamp** | When the request or connection occurred | Yes | Yes | +| **Protocol** | `http`, `tcp`, `udp`, or `tls` | Yes | Yes | +| **Method** | HTTP method (GET, POST, etc.). For L4, displays the protocol name. | Yes | Protocol name | +| **Host / URL** | Domain and path for HTTP. Host and listen port for L4. | `host/path` | `host:port` | +| **Status Code** | HTTP status code (200, 401, 403, 500, etc.) | Yes | Empty | +| **Duration** | Request or connection duration in milliseconds | Yes | Yes | +| **Bytes Uploaded** | Bytes sent from client to backend | Yes | Yes | +| **Bytes Downloaded** | Bytes sent from backend to client | Yes | Yes | +| **Source IP** | The client's IP address | Yes | Yes | +| **Location** | Country, city, and subdivision based on source IP geolocation | Yes | Yes | +| **Auth Method** | Authentication method used (SSO, password, PIN, header, or none) | Yes | N/A | +| **User** | The authenticated user's ID (if SSO was used) | Yes | N/A | +| **Reason** | Reason for denial, if applicable | Yes | Yes | ## Understanding log entries -Log entries fall into three categories based on the HTTP status code returned: +### HTTP log entries -- **Allowed requests** - Successful requests show a `2xx` status code along with the authentication method used to access the service. -- **Denied requests** - Failed authentication attempts show `401` or `403` status codes with a reason explaining why the request was denied, such as an invalid password or missing SSO session. -- **Errors** - Backend errors or proxy issues show `5xx` status codes. These typically indicate that the target service is unreachable or returned an error. +HTTP log entries fall into three categories based on the status code: + +- **Allowed requests**: successful requests show a `2xx` status code along with the authentication method used to access the service. +- **Denied requests**: failed authentication or access restriction blocks show `401` or `403` status codes with a reason explaining why the request was denied (e.g., invalid password, missing SSO session, IP restricted, country restricted). +- **Errors**: backend errors or proxy issues show `5xx` status codes. These typically indicate that the target service is unreachable or returned an error. + +### L4 log entries + +L4 entries are logged when the connection closes and record the total bytes transferred in each direction and the connection duration. L4 entries do not have HTTP status codes. + +Denied L4 connections (blocked by access restrictions) are logged immediately with a deny reason. Since L4 services do not support authentication, denials come from access restrictions only. + +### Deny reasons + +The following deny reasons can appear for both HTTP and L4 services: + +| Reason | Description | +|--------|-------------| +| `ip_restricted` | The client IP was blocked by a CIDR access restriction | +| `country_restricted` | The client's country was blocked by a country access restriction | +| `geo_unavailable` | Country restrictions are configured but the GeoIP database is unavailable (fail-closed) | ## Use cases diff --git a/src/pages/manage/reverse-proxy/authentication.mdx b/src/pages/manage/reverse-proxy/authentication.mdx index b6051a3a..594fd28a 100644 --- a/src/pages/manage/reverse-proxy/authentication.mdx +++ b/src/pages/manage/reverse-proxy/authentication.mdx @@ -1,11 +1,11 @@ -import {Note} from "@/components/mdx" +import {Note, Warning} from "@/components/mdx" export const description = - 'Configure SSO, password, and PIN authentication methods for NetBird Reverse Proxy services to control who can access your exposed applications.' + 'Configure SSO, password, PIN, and header authentication methods, plus IP and country access restrictions, for NetBird Reverse Proxy services.' # Reverse Proxy Authentication -NetBird Reverse Proxy supports multiple authentication methods to control who can access your exposed services. You can enable one or more methods on each service, or leave a service completely public. Authentication is configured per service in the **Authentication** tab when creating or editing a service. +NetBird Reverse Proxy supports multiple authentication methods and connection-level access restrictions to control who can access your exposed services. You can enable one or more methods on each service, or leave a service completely public. Authentication and access restrictions are configured per service in the **Authentication** tab when creating or editing a service.

Authentication tab showing all available authentication methods @@ -13,7 +13,11 @@ NetBird Reverse Proxy supports multiple authentication methods to control who ca ## Authentication methods -NetBird offers three authentication methods, each suited to different access patterns. You can enable any combination of them on a single service. +NetBird offers four authentication methods, each suited to different access patterns. You can enable any combination of them on a single service. + + + 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. + ### SSO (Single Sign-On) @@ -72,6 +76,29 @@ PIN code authentication works similarly to password authentication but is limite **Best for:** Quick access scenarios, kiosk-style interfaces, or situations where a simple numeric code is easier to share than a full password. +### Header Authentication + +Header authentication validates a static header value on each request. This is designed for programmatic or machine-to-machine access where clients can include a custom HTTP header with their requests. The proxy checks the header before forwarding the request to your backend and strips the header so that authentication credentials are not leaked to the backend. + +NetBird supports three header presets to simplify configuration: + +| Preset | Header | Value format | Example value | +|--------|--------|-------------|---------------| +| **Basic Auth** | `Authorization` | `Basic base64(username:password)` | `Basic dXNlcjpwYXNz` | +| **Bearer Token** | `Authorization` | `Bearer ` | `Bearer my-secret-token` | +| **Custom Header** | Any header name you choose | Any value | `X-API-Key: my-api-key` | + +You can configure multiple header entries on a single service. If multiple headers are configured, a request that matches **any one** of them is granted access (OR logic). + +**Key details:** + +- Header values are hashed with **Argon2id** before being stored, the same as passwords and PINs. The plaintext value is never stored. +- The matching header is stripped from the request before it is forwarded to the backend. +- Sessions last **24 hours** before re-authentication is required. +- Header authentication works at the HTTP level, so it is available for HTTP services. It is not available for L4 services. + +**Best for:** API clients, CI/CD pipelines, webhooks, monitoring probes, and any scenario where a browser-based login flow is not practical. Also useful alongside SSO: team members authenticate via SSO in a browser, while automated systems use header auth. + ### No authentication (public access) Services can also be configured without any authentication. When no authentication method is enabled, anyone with the service URL can access it without any restrictions. @@ -97,13 +124,67 @@ Common combinations include: | Combination | Use case | |-------------|----------| | **SSO + Password** | Team members use SSO; external collaborators use a shared password | +| **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 | -| **SSO + Password + PIN Code** | Maximum flexibility with all methods available | +| **Any auth + Access Restrictions** | IP/country restrictions as a first layer, then authentication for identity | + +## Access restrictions + +Access restrictions control which connections are allowed to reach your service based on the client's IP address or geographic location. Unlike authentication methods, access restrictions operate at the connection level and work for both HTTP and L4 services. + +Access restrictions are evaluated **before** authentication. If a connection is blocked by an IP or country rule, it is rejected immediately without any authentication check. + +### IP CIDR restrictions + +You can define IP allowlists and blocklists using CIDR notation: + +- **Allowed CIDRs**: if non-empty, only connections from IPs matching these CIDRs are permitted. All other IPs are rejected. +- **Blocked CIDRs**: connections from IPs matching these CIDRs are rejected. Evaluated after the allowed list. + +The evaluation order is: if an allowed list is present, the IP must match it first. Then the blocked list is checked. This means you can use an allowed list to broadly permit a range, then use the blocked list to carve out exceptions. + +**Example**: allow your office network but block a specific subnet: + +| Field | Value | +|-------|-------| +| Allowed CIDRs | `203.0.113.0/24` | +| Blocked CIDRs | `203.0.113.128/25` | + +### Country restrictions + +You can restrict access based on the client's country, determined by GeoIP lookup on the source IP address: + +- **Allowed countries**: if non-empty, only connections from these countries are permitted. Specify ISO 3166-1 alpha-2 country codes (e.g., `US`, `DE`, `GB`). +- **Blocked countries**: connections from these countries are rejected. + +The evaluation logic mirrors CIDR restrictions: if an allowed list is present, the country must match. Then the blocked list is checked. + + + Country restrictions require a GeoIP database. On self-hosted deployments, the proxy must have the MaxMind GeoLite2 database configured. If the database is unavailable and country restrictions are configured, all connections are denied (fail-closed). See [Geolocation Database](/selfhosted/geo-support) for setup instructions. + + + + GeoIP accuracy depends on the database quality and the client's IP address. VPN and proxy users may appear from a different country than their physical location. + + +### Combining restrictions with authentication + +Access restrictions and authentication methods are independent layers: + +1. **Connection arrives** at the proxy. +2. **Access restrictions** are evaluated first: IP CIDRs, then country. If the connection is blocked, it is rejected with no further processing. +3. **Authentication** is evaluated next (for HTTP services): SSO, password, PIN, or header auth. +4. If both layers pass, the request is forwarded to the backend. + +This layered approach lets you, for example, restrict a service to your corporate IP ranges while still requiring SSO for identity verification. Or you can use access restrictions as the sole protection for an L4 service that cannot use browser-based auth. ## Configuring authentication -All authentication settings are managed in the **Authentication** tab of the service creation or edit modal. Navigate to **Reverse Proxy** > **Services**, then either click **Add Service** to create a new service or click an existing service to edit it. +Authentication and access control are configured in separate tabs of the service creation or edit modal. Navigate to **Reverse Proxy** > **Services**, then either click **Add Service** to create a new service or click an existing service to edit it. + +- **Authentication** tab (HTTP services only): SSO, password, PIN, and header authentication +- **Access Control** tab (all service modes): IP CIDR and country restrictions ### Setting up SSO @@ -134,6 +215,35 @@ All authentication settings are managed in the **Authentication** tab of the ser 4. Enter a numeric PIN in the input field. 5. Click **Save** (or **Save Changes** when editing). +### Setting up header authentication + +1. Open the service modal (create or edit). +2. Switch to the **Authentication** tab. +3. Click **Header Auth**. +4. Select a preset type: **Basic Auth**, **Bearer Token**, or **Custom Header**. +5. Fill in the required fields: + - For **Basic Auth**: enter a username and password. The value is automatically encoded as `Basic base64(username:password)`. + - For **Bearer Token**: enter the token value. The value is automatically prefixed with `Bearer `. + - For **Custom Header**: enter the header name (e.g., `X-API-Key`) and the expected value. +6. To add additional headers, click **Add Another Header**. Any matching header grants access. +7. Click **Save** (or **Save Changes** when editing). + +### Setting up access restrictions + +1. Open the service modal (create or edit). +2. Switch to the **Access Control** tab. This tab is available for all service modes (HTTP and L4). +3. To restrict by IP: + - Enter CIDRs in the **Allowed CIDRs** field to create an allowlist (e.g., `10.0.0.0/8`, `203.0.113.0/24`). + - Enter CIDRs in the **Blocked CIDRs** field to create a blocklist. +4. To restrict by country: + - Select countries in the **Allowed Countries** field to create a country allowlist. + - Select countries in the **Blocked Countries** field to create a country blocklist. +5. Click **Save** (or **Save Changes** when editing). + + + Access restrictions apply immediately to new connections. Existing connections that were established before the restriction was added are not affected until they reconnect. + + ### Removing authentication To remove an authentication method from a service: @@ -161,3 +271,4 @@ Authenticated sessions for reverse proxy services are managed using JWT (JSON We - [Access Logs](/manage/reverse-proxy/access-logs) - monitor and audit traffic to your reverse proxy services - [Single Sign-On](/manage/team/single-sign-on) - configure your identity provider for SSO across NetBird - [Provision Users and Groups](/manage/team/idp-sync) - sync users and groups from your identity provider +- [Geolocation Database](/selfhosted/geo-support) - configure MaxMind GeoLite2 for country-based access restrictions (self-hosted) diff --git a/src/pages/manage/reverse-proxy/custom-domains.mdx b/src/pages/manage/reverse-proxy/custom-domains.mdx index f17e67b8..3dd52afa 100644 --- a/src/pages/manage/reverse-proxy/custom-domains.mdx +++ b/src/pages/manage/reverse-proxy/custom-domains.mdx @@ -168,5 +168,5 @@ Each custom domain must be unique across all NetBird accounts. If you receive an ## Related pages - [Reverse Proxy Overview](/manage/reverse-proxy) - learn how the reverse proxy feature works -- [Authentication](/manage/reverse-proxy/authentication) - configure SSO, password, and PIN authentication for services +- [Authentication](/manage/reverse-proxy/authentication) - configure SSO, password, PIN, and header authentication, plus access restrictions - [Access Logs](/manage/reverse-proxy/access-logs) - monitor traffic to your reverse proxy services diff --git a/src/pages/manage/reverse-proxy/expose-from-cli.mdx b/src/pages/manage/reverse-proxy/expose-from-cli.mdx index a55e08c0..576b3db9 100644 --- a/src/pages/manage/reverse-proxy/expose-from-cli.mdx +++ b/src/pages/manage/reverse-proxy/expose-from-cli.mdx @@ -1,13 +1,13 @@ import {Note, Warning} from "@/components/mdx" export const description = - 'Expose local HTTP services to the public internet directly from the command line using `netbird expose`, with optional authentication, custom domains, and automatic session management.' + 'Expose local HTTP and L4 services to the public internet directly from the command line using `netbird expose`, with optional authentication, custom domains, and automatic session management.' # Expose from CLI -The `netbird expose` command lets peers expose local HTTP services to the public internet through the NetBird reverse proxy without using the dashboard. Services created this way are **ephemeral** — they exist only while the command is running and are automatically removed when you stop the command or the session expires. +The `netbird expose` command lets peers expose local services to the public internet through the NetBird reverse proxy without using the dashboard. Services created this way are **ephemeral**: they exist only while the command is running and are automatically removed when you stop the command or the session expires. -This is useful for quick demos, temporary access to development servers, webhook receivers, or sharing local work with teammates. +This supports both HTTP and L4 (TCP, UDP, TLS) protocols, making it useful for quick demos, temporary access to development servers, webhook receivers, database tunnels, or sharing local work with teammates. **Availability:** This feature requires the NetBird management server to have the Reverse Proxy module enabled. For self-hosted deployments, ensure your proxy instance is deployed and connected. See [Reverse Proxy](/manage/reverse-proxy) for setup details. @@ -30,7 +30,7 @@ An account administrator must enable peer expose before any peer can use the `ne 1. Navigate to **Settings** > **Clients** in the NetBird dashboard. 2. Scroll to the **Peer Expose** section. 3. Toggle **Enable Peer Expose** on. -4. Select specific **peer groups** that are allowed to expose services. Groups without proper permission with get a `PermissionDenied` error. +4. Select specific **peer groups** that are allowed to expose services. Groups without proper permission will get a `PermissionDenied` error. 5. Click **Save Changes**. ### From the API @@ -67,13 +67,50 @@ Service exposed successfully! URL: https://myapp-a1b2c3.proxy.example.com Domain: myapp-a1b2c3.proxy.example.com Protocol: http - Port: 8080 + Internal: 8080 Press Ctrl+C to stop exposing. ``` The service is now accessible at the displayed URL. Press `Ctrl+C` to stop exposing and remove the service. +### Exposing L4 services + +To expose a TCP, UDP, or TLS service, use the `--protocol` flag: + +```shell +netbird expose --protocol tcp 5432 +``` + +For L4 services, the output includes the external port on the proxy cluster: + +``` +Service exposed successfully! + Name: myapp-a1b2c3 + URL: myapp-a1b2c3.proxy.example.com:5432 + Protocol: tcp + Internal: 5432 + External: 5432 + +Press Ctrl+C to stop exposing. +``` + +By default, the external port matches the target port. Use `--with-external-port` to specify a different one: + +```shell +netbird expose --protocol tcp --with-external-port 15432 5432 +``` + +If the proxy cluster does not support custom ports (e.g., NetBird shared cloud clusters), the port is auto-assigned. When you explicitly specify `--with-external-port` but the cluster overrides your choice, the output indicates the reassignment: + +``` + External: 38721 + + Note: requested port 15432 was reassigned +``` + +If you do not specify `--with-external-port`, the assigned port is shown without a reassignment note. + ## Command reference ```shell @@ -90,13 +127,18 @@ netbird expose [flags] | Flag | Type | Default | Description | |------|------|---------|-------------| -| `--protocol` | string | `http` | Protocol to use: `http` or `https` (e.g. `--protocol http`). | -| `--with-pin` | string | | Protect the exposed service with a 6-digit PIN (e.g. `--with-pin 123456`). Must be exactly 6 digits. | -| `--with-password` | string | | Protect the exposed service with a password (e.g. `--with-password my-secret`). Cannot be empty. | -| `--with-user-groups` | strings | | Restrict access to specific user groups via SSO (e.g. `--with-user-groups devops,Backend`). Cannot be empty. | -| `--with-custom-domain` | string | | Custom domain for the exposed service, must be configured to your account (e.g. `--with-custom-domain myapp.example.com`). | +| `--protocol` | string | `http` | Protocol to use: `http`, `https`, `tcp`, `udp`, or `tls`. | +| `--with-external-port` | uint16 | target port | Public-facing port on the proxy cluster. L4 only (TCP, UDP, TLS). Defaults to the target port. | +| `--with-pin` | string | | Protect the exposed service with a 6-digit PIN. HTTP only. | +| `--with-password` | string | | Protect the exposed service with a password. HTTP only. | +| `--with-user-groups` | strings | | Restrict access to specific user groups via SSO. HTTP only. | +| `--with-custom-domain` | string | | Custom domain for the exposed service, must be configured in your account. | | `--with-name-prefix` | string | | Prefix for the generated service name (e.g. `--with-name-prefix my-app`). | + + Authentication flags (`--with-pin`, `--with-password`, `--with-user-groups`) are only supported for HTTP/HTTPS protocols. L4 protocols (TCP, UDP, TLS) do not support these flags because there is no HTTP layer to serve a login page. Similarly, `--with-external-port` is only supported for L4 protocols. + + ## Authentication By default, exposed services are publicly accessible to anyone who knows the URL. You can protect them using one or more authentication methods. @@ -238,12 +280,13 @@ If the peer does not have permission, the command returns a "permission denied" | Property | Dashboard services | CLI expose services | |----------|-------------------|---------------------| | **Created via** | Dashboard or API | `netbird expose` command | -| **Lifecycle** | Permanent until manually deleted | Ephemeral — removed when command exits or session expires | +| **Lifecycle** | Permanent until manually deleted | Ephemeral: removed when command exits or session expires | | **TTL** | None | 90 seconds, auto-renewed every 30 seconds | -| **Multiple targets** | Yes (path-based routing) | Single target (the local port) | +| **Service modes** | HTTP, TCP, UDP, TLS | HTTP, HTTPS, TCP, UDP, TLS | +| **Multiple targets** | Yes (path-based routing for HTTP) | Single target (the local port) | | **Custom domains** | Yes | Yes (if pre-configured) | -| **Authentication** | SSO, Password, PIN | SSO (user groups), Password, PIN | -| **Advanced settings** | Host header, redirect rewriting | Not available | +| **Authentication** | SSO, Password, PIN, Header Auth, Access Restrictions | SSO (user groups), Password, PIN (HTTP only) | +| **Advanced settings** | Host header, redirect rewriting, PROXY protocol, session timeout | Not available | | **Visibility** | Always shown in dashboard | Shown while active | | **Rate limit** | None | Max 10 per peer | | **Source label** | Permanent | Ephemeral | @@ -289,7 +332,7 @@ The `--with-name-prefix` value contains invalid characters. The prefix must be: ### "unsupported protocol" -The `--protocol` flag only accepts `http` or `https`. Other protocols (e.g. TCP, UDP) are not yet supported for peer expose. +The `--protocol` flag accepts `http`, `https`, `tcp`, `udp`, or `tls`. Any other value is rejected. ### Service URL returns connection error after Ctrl+C @@ -337,10 +380,34 @@ Temporarily expose a local webhook endpoint for testing: netbird expose 9000 --with-name-prefix webhooks ``` +### Database tunnel + +Expose a local PostgreSQL instance over TCP: + +```shell +netbird expose --protocol tcp 5432 +``` + +### Game server + +Expose a local UDP game server on a specific external port: + +```shell +netbird expose --protocol udp --with-external-port 27015 27015 +``` + +### TLS passthrough + +Expose a service that handles its own TLS termination: + +```shell +netbird expose --protocol tls --with-custom-domain tls.example.com 4443 +``` + ## Related pages - [Reverse Proxy](/manage/reverse-proxy) - overview of the reverse proxy feature, dashboard setup, and concepts -- [Authentication](/manage/reverse-proxy/authentication) - detailed guide on SSO, password, and PIN authentication +- [Authentication](/manage/reverse-proxy/authentication) - SSO, password, PIN, and header authentication, plus access restrictions - [Custom Domains](/manage/reverse-proxy/custom-domains) - configure your own domain names - [Access Logs](/manage/reverse-proxy/access-logs) - monitor traffic to your reverse proxy services - [CLI Reference](/get-started/cli#expose) - `netbird expose` command reference diff --git a/src/pages/manage/reverse-proxy/index.mdx b/src/pages/manage/reverse-proxy/index.mdx index 7f17bb7f..f130372f 100644 --- a/src/pages/manage/reverse-proxy/index.mdx +++ b/src/pages/manage/reverse-proxy/index.mdx @@ -1,11 +1,11 @@ import {Note, Warning} from "@/components/mdx" export const description = - 'Expose internal services to the public internet with automatic TLS, authentication, and traffic routing through the NetBird mesh network.' + 'Expose internal services to the public internet with automatic TLS, authentication, access restrictions, and traffic routing through the NetBird mesh network.' # Reverse Proxy -NetBird Reverse Proxy lets you expose internal services running on peers or behind network resources to the public internet. NetBird handles TLS termination, optional authentication, and proxies incoming traffic through the WireGuard mesh to reach the target service - all without opening ports or configuring firewalls on your internal machines. +NetBird Reverse Proxy lets you expose internal services running on peers or behind network resources to the public internet. NetBird handles TLS termination, optional authentication and access restrictions, and proxies incoming traffic through the NetBird mesh to reach the target service, all without opening ports or configuring firewalls on your internal machines. **Availability:** Reverse Proxy is available for both **cloud** and **self-hosted** deployments and is currently in **beta**. @@ -19,13 +19,18 @@ NetBird Reverse Proxy lets you expose internal services running on peers or behi ## How it works -When you create a reverse proxy service, NetBird provisions a public domain with an automatic TLS certificate. Incoming HTTPS requests to that domain are terminated at the NetBird proxy cluster, then forwarded through an encrypted WireGuard tunnel to the target peer or network resource running your application. The target service only needs to be reachable within your NetBird network - it does not need a public IP address or open ports. +When you create a reverse proxy service, NetBird provisions a public domain with an automatic TLS certificate. Incoming traffic to that domain is received at the NetBird proxy cluster, then forwarded through an encrypted NetBird tunnel to the target peer or network resource running your application. The target service only needs to be reachable within your NetBird network: it does not need a public IP address or open ports.

Reverse proxy traffic flow diagram showing User to Proxy Service (TLS) through WireGuard tunnel to either a NetBird Peer directly or via a Routing Peer to a Network Resource

-You can optionally require authentication (SSO via your configured IdP, password, or PIN) before users can reach the service, ensuring that even publicly accessible URLs remain protected. +NetBird supports two categories of service: + +- **HTTP services** operate at Layer 7. The proxy terminates TLS at the edge and forwards HTTP requests to your backend. This mode supports path-based routing, host header forwarding, redirect rewriting, and browser-based authentication (SSO, password, PIN). +- **L4 services** (TCP, UDP, TLS) operate at Layer 4. The proxy forwards raw connections or datagrams directly to your backend without inspecting application-layer content. TLS mode performs SNI-based routing, passing the encrypted connection through to the backend without terminating it. + +You can optionally require authentication before users can reach the service, and restrict access by IP address or country. See [Authentication](/manage/reverse-proxy/authentication) for all available options. ## Concepts @@ -33,15 +38,34 @@ You can optionally require authentication (SSO via your configured IdP, password A service is the core configuration unit of the Reverse Proxy. Each service maps a public domain to one or more internal targets and defines how traffic is authenticated and forwarded. A service consists of: +- **Service mode** - HTTP (Layer 7) or TCP/UDP/TLS (Layer 4) - **Domain** - the public URL where the service is reachable - **Targets** - one or more backend destinations that handle incoming requests -- **Authentication** - optional SSO, password, or PIN protection -- **Settings** - advanced options for host header forwarding and redirect rewriting +- **Authentication** - optional SSO, password, PIN, or header-based protection +- **Access restrictions** - optional IP CIDR and country-based access control +- **Settings** - advanced options (varies by service mode) - **Enabled/Disabled toggle** - turn the service on or off without deleting it +### Service modes + +The service mode determines how the proxy handles traffic between clients and your backend. + +| Mode | Layer | Description | +|------|-------|-------------| +| **HTTP** | L7 | TLS termination at the proxy, HTTP-level forwarding. Supports path-based routing, host header forwarding, redirect rewriting, and browser-based authentication (SSO, password, PIN). | +| **TCP** | L4 | Raw TCP relay. The proxy accepts TCP connections on a dedicated port and forwards them to your backend. | +| **UDP** | L4 | UDP relay with session tracking. The proxy accepts UDP packets on a dedicated port and forwards them to your backend. Sessions are reaped after an idle timeout. | +| **TLS** | L4 | TLS passthrough with SNI-based routing. The proxy inspects the TLS ClientHello to read the SNI hostname and forwards the encrypted connection to your backend without terminating TLS. | + +L4 services (TCP, UDP, TLS) listen on a dedicated port on the proxy cluster. Depending on the cluster, the port may be auto-assigned or you can specify one manually. The proxy cluster's `supports_custom_ports` capability determines whether manual port selection is available. + + + L4 services do not support browser-based authentication (SSO, password, PIN) or header authentication because there is no HTTP layer. You can use [access restrictions](/manage/reverse-proxy/authentication#access-restrictions) (IP CIDR and country rules) to protect L4 services. + + ### Targets -A target defines where proxied traffic is sent within your NetBird network. Each service can have multiple targets for path-based routing. Every target specifies a type, protocol, port, and optional path. +A target defines where proxied traffic is sent within your NetBird network. Every target specifies a type and port. HTTP services additionally support path-based routing. | Type | Description | How to select | |------|-------------|---------------| @@ -50,13 +74,21 @@ A target defines where proxied traffic is sent within your NetBird network. Each | **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 | -Each target also has the following properties: +Target properties vary by service mode: +**HTTP services:** - **Path** (optional) - a URL path prefix for path-based routing (e.g., `/api`). See [Path-based routing](#path-based-routing) below. - **Protocol** - `HTTP` or `HTTPS`, depending on what the backend service speaks - **Port** - the port on the target machine (defaults to `80` for HTTP, `443` for HTTPS) - **Enabled/Disabled toggle** - individually enable or disable targets without removing them +**L4 services (TCP, UDP, TLS):** +- **Type** - same Peer, Host, Domain, or Subnet selection as HTTP services +- **Port** - the port on the target machine +- **Enabled/Disabled toggle** - individually enable or disable targets without removing them + +L4 targets do not support path-based routing or HTTP/HTTPS protocol selection. + ### Domains Every service needs a domain. The available domain types depend on whether you are using NetBird Cloud or a self-hosted deployment. @@ -91,15 +123,16 @@ All domain types receive automatic TLS certificates managed by the proxy. You can protect a service with one or more authentication methods. When multiple methods are enabled, users can choose which one to use when accessing the service. -| Method | Description | -|--------|-------------| -| **SSO (Single Sign-On)** | Authenticate via your identity provider using OIDC. You can optionally restrict access to specific user groups. | -| **Password** | Protect with a shared password that you define when configuring the service. | -| **PIN Code** | Protect with a numeric PIN code. | -| **No authentication** | The service is publicly accessible without any authentication. | +| Method | HTTP services | L4 services | Description | +|--------|:---:|:---:|-------------| +| **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 or country. Works at the connection level, so it applies to all service modes. | - If you save a service with no authentication configured, the dashboard will display a warning. Public services are accessible to anyone on the internet who knows the URL. + 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. For detailed configuration instructions, see [Authentication](/manage/reverse-proxy/authentication). @@ -129,7 +162,7 @@ Self-hosted deployments require a separate NetBird proxy instance (`netbirdio/ne ### TLS certificate configuration -The proxy supports two modes for TLS certificate management: +The proxy supports three modes for TLS certificate management: **ACME mode (Let's Encrypt)** - The proxy automatically provisions TLS certificates for each domain using Let's Encrypt. Enable this mode with: @@ -152,7 +185,7 @@ The default ACME challenge type (`tls-alpn-01`) validates domain ownership by re If any of these requirements cannot be met in your environment, switch to the `http-01` challenge type by setting `NB_PROXY_ACME_CHALLENGE_TYPE=http-01`. The HTTP-01 challenge validates over port 80 using a plain HTTP request and does not depend on ALPN protocol support. However, it requires port 80 to be accessible from the internet. -**Static certificate mode** - Provide your own certificate and key files. This is useful for wildcard certificates or certificates from a corporate CA. Configure with: +**Static certificate mode** - Provide your own certificate and key files. This is useful for certificates from a corporate CA or when you manage certificates externally. Configure with: | Environment variable | Description | |---------------------|-------------| @@ -162,6 +195,14 @@ If any of these requirements cannot be met in your environment, switch to the `h Static certificates support hot-reload through file watching. When the certificate or key file changes on disk, the proxy picks up the new files automatically without requiring a restart. +**Wildcard certificate mode** - Point the proxy at a directory containing wildcard certificate and key pairs. The proxy loads all certificates from the directory, matches them against incoming SNI hostnames, and serves the appropriate wildcard certificate automatically. This is useful when you have a wildcard certificate (e.g., `*.proxy.example.com`) that should cover all services under that domain. Configure with: + +| Environment variable | Description | +|---------------------|-------------| +| `NB_PROXY_WILDCARD_CERT_DIR` | Directory containing wildcard certificate and key pairs. The proxy reads all certificate files in this directory and matches them by SNI. | + +Wildcard certificates support hot-reload through file watching. When certificate files in the directory are updated, the proxy reloads them automatically without requiring a restart. Services that match a loaded wildcard domain bypass ACME certificate provisioning entirely. + ### High availability For self-hosted deployments, multiple proxy instances configured with the same `NB_PROXY_DOMAIN` value form a single proxy cluster, providing automatic failover. See [Running Multiple Proxy Instances](/selfhosted/maintenance/scaling/multiple-proxy-instances) for setup instructions covering token management, TLS certificates, and monitoring across instances. @@ -191,27 +232,28 @@ Navigate to **Reverse Proxy** > **Services** in the NetBird dashboard and click In the **Details** tab: -1. Enter a **subdomain** for your service (e.g., `myapp`). -2. Select a **base domain**. Cloud users see domains with a **Free** badge (e.g., `abc123.eu.proxy.netbird.io`). Self-hosted users see domains with a **Cluster** badge (e.g., `proxy.mycompany.com`, based on their deployed proxy instances). You can also select a custom domain you have already configured. -3. Click **Add Target** to define where traffic should be sent. +1. Select a **service mode**. Choose **HTTP** for web applications, or **TCP**, **UDP**, or **TLS** for Layer 4 services. See [Service modes](#service-modes) for details on each mode. +2. Enter a **subdomain** for your service (e.g., `myapp`). +3. Select a **base domain**. Cloud users see domains with a **Free** badge (e.g., `abc123.eu.proxy.netbird.io`). Self-hosted users see domains with a **Cluster** badge (e.g., `proxy.mycompany.com`, based on their deployed proxy instances). You can also select a custom domain you have already configured. +4. For L4 services, set the **listen port** that the proxy will accept connections on. Some clusters auto-assign ports; others allow you to specify one manually. +5. Click **Add Target** to define where traffic should be sent.

Add Service modal showing the Details tab

-4. In the target configuration, select the **type** (Peer, Host, Domain, or Subnet), then choose the specific peer or resource. -5. Set the **protocol** (HTTP or HTTPS) and **port** for the target. -6. Optionally, enter a **path** if you are using path-based routing. +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**.

Add Target configuration modal

-You can add multiple targets to route different URL paths to different backend services. +You can add multiple targets. HTTP services support path-based routing across targets. -### Step 3: Configure authentication +### Step 3: Configure authentication (HTTP only) -Switch to the **Authentication** tab to configure how users are authenticated before reaching your service. +Switch to the **Authentication** tab to configure how users are authenticated before reaching your service. This tab is only available for HTTP services.

Add Service modal showing the Authentication tab @@ -220,23 +262,38 @@ Switch to the **Authentication** tab to configure how users are authenticated be - 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. +- Enable **Header Authentication** to require a specific header value (API key, Bearer token, or Basic auth credentials). Useful for machine-to-machine access. - Leave all methods disabled for public (unauthenticated) access. You can enable multiple authentication methods simultaneously. Users will be able to choose their preferred method when accessing the service. +### Step 3b: Configure access control + +Switch to the **Access Control** tab to restrict access by IP address or country. This tab is available for all service modes (HTTP and L4). + +- Add **allowed CIDRs** or **blocked CIDRs** to restrict by IP range. +- Add **allowed countries** or **blocked countries** to restrict by geographic location. + +Access restrictions are evaluated before authentication: if a connection is blocked by an IP or country rule, it is rejected before any authentication check. + ### Step 4: Configure advanced settings -Switch to the **Settings** tab to adjust advanced proxy behavior. +Switch to the **Settings** tab to adjust advanced proxy behavior. The available settings depend on the service mode.

Add Service modal showing the Settings tab

+**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. +**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. +- **Session Idle Timeout** (UDP only) - how long a UDP session can be idle before the proxy reaps it. Specified as a duration string (e.g., `30s`, `2m`). Defaults to 30 seconds. + **Backend configuration may be required.** If your backend service has a "trusted proxies", "known hosts", or "allowed networks" setting (common in Jellyfin, Home Assistant, Plex, Nextcloud, and others), you must configure it to trust the NetBird IP range. Without this, the backend may reject proxied requests or fail to read the real client IP. See [Backend Service Configuration](/manage/reverse-proxy/service-configuration) for details and per-service examples. @@ -267,6 +324,47 @@ Within a service, you can: - **Remove targets** - remove a target to stop routing traffic to that backend - **Enable or disable targets** - toggle individual targets on or off without removing them from the service +## Port allocation for L4 services + +L4 services (TCP, UDP, TLS) require a dedicated port on the proxy cluster. How ports are assigned depends on whether the proxy cluster supports custom port selection: + +- **Custom port selection available**: you choose the exact port the proxy listens on. This is useful when clients expect a well-known port (e.g., 5432 for PostgreSQL, 3306 for MySQL). Self-hosted proxy clusters support this when configured to allow it. +- **Auto-assigned ports only**: the proxy cluster automatically assigns an available port. This is the case for NetBird's shared cloud proxy clusters, where port allocation is managed to avoid conflicts between accounts. The assigned port is shown in the service details after creation. + +The dashboard indicates whether a proxy cluster supports custom ports when you select the domain. If custom ports are not supported, the listen port field is read-only and populated after creation. + + + Each port on a proxy cluster can only be used by one service at a time. If you specify a port that is already in use by another service, creation will fail. L4 listen ports also cannot conflict with the proxy's tunnel port. + + + + The listen port for an L4 service is separate from the target port. For example, a service could listen on port 15432 on the proxy cluster and forward traffic to port 5432 on the backend peer. Clients connect to the proxy cluster address on the listen port. + + + + **Self-hosted Docker deployments:** The default Docker Compose configuration only routes port 443 (via Traefik TLS passthrough) to the proxy container. L4 services that listen on additional TCP or UDP ports require you to manually expose those ports in your `docker-compose.yml`. See the [migration guide](/selfhosted/migration/enable-reverse-proxy#exposing-l4-ports) for instructions. + + +### How services share ports + +The proxy's main port always runs an SNI router that peeks at the TLS ClientHello to read the requested hostname, then routes the connection to the matching service. This allows multiple service modes to share the same port. + +**On the main port**, HTTP and TLS services coexist via SNI routing: +- Each incoming connection is matched against configured domains. +- If the SNI hostname matches an **HTTP** service, the connection is forwarded to the HTTP reverse proxy for L7 handling. +- If the SNI hostname matches a **TLS** service, the encrypted connection is passed through directly to the backend without TLS termination. +- If the SNI hostname does not match any service, the connection falls through to the HTTP reverse proxy, which returns an error since no matching service exists. +- Connections with no SNI (e.g., TLS 1.3 with Encrypted Client Hello) follow the same fallback path. + + + Do not configure an HTTP and a TLS service with the same hostname. The HTTP route takes priority and the TLS service becomes unreachable. Use different domain names for each. + + +**On custom ports**, TLS and TCP services can coexist: +- TLS connections are matched by SNI and passed through to the backend. +- Connections that do not match any SNI route (or are not TLS at all) fall back to the TCP relay. +- This is useful for running a TLS passthrough alongside a plain TCP catch-all on the same port. + ## Path-based routing When a service has multiple targets, you can assign each target a unique path prefix to route different URL paths to different backends. For example: @@ -291,13 +389,13 @@ The Networks page also displays a badge on each resource indicating how many rev ## Expose from CLI -In addition to creating services through the dashboard, peers can expose local services directly from the command line using the `netbird expose` command. This creates a temporary (ephemeral) service that lives only as long as the command is running — useful for quick demos, development sharing, or temporary webhook endpoints. +In addition to creating services through the dashboard, peers can expose local services directly from the command line using the `netbird expose` command. This creates a temporary (ephemeral) service that lives only as long as the command is running, useful for quick demos, development sharing, or temporary webhook endpoints. ```shell netbird expose 8080 ``` -The command supports optional authentication (`--with-pin`, `--with-password`, `--with-user-groups`), custom domains (`--with-custom-domain`), and name prefixes (`--with-name-prefix`). +The command supports HTTP and L4 protocols (`--protocol`), optional authentication (`--with-pin`, `--with-password`, `--with-user-groups`), custom domains (`--with-custom-domain`), and name prefixes (`--with-name-prefix`). For L4 services, use `--with-external-port` to specify the listen port on the proxy cluster. The Peer Expose feature must be enabled by an account administrator in **Settings** > **Clients** before peers can use this command. @@ -310,7 +408,7 @@ For the complete guide including setup, authentication options, session lifecycl - [Expose from CLI](/manage/reverse-proxy/expose-from-cli) - expose local services from the command line using `netbird expose` - [Multiple Proxy Instances](/selfhosted/maintenance/scaling/multiple-proxy-instances) - deploy multiple proxy instances for high availability and redundancy - [Custom Domains](/manage/reverse-proxy/custom-domains) - configure your own domain names for reverse proxy services -- [Authentication](/manage/reverse-proxy/authentication) - detailed guide on SSO, password, and PIN authentication options +- [Authentication](/manage/reverse-proxy/authentication) - SSO, password, PIN, header authentication, and access restrictions - [Access Logs](/manage/reverse-proxy/access-logs) - monitor and audit traffic to your reverse proxy services - [Networks](/manage/networks) - configure internal networks and resources - [Access Control](/manage/access-control/manage-network-access) - manage policies that control access to your network diff --git a/src/pages/selfhosted/maintenance/upgrade.mdx b/src/pages/selfhosted/maintenance/upgrade.mdx index 632a28e8..d295c9f0 100644 --- a/src/pages/selfhosted/maintenance/upgrade.mdx +++ b/src/pages/selfhosted/maintenance/upgrade.mdx @@ -48,10 +48,18 @@ To upgrade NetBird to the latest version: ```bash docker compose pull netbird-server dashboard ``` + If you have the [Reverse Proxy](/manage/reverse-proxy) enabled, also pull the proxy image: + ```bash + docker compose pull proxy + ``` 4. Restart the NetBird containers with the new images: ```bash docker compose up -d --force-recreate netbird-server dashboard ``` + If you pulled the proxy image above, include it in the restart: + ```bash + docker compose up -d --force-recreate netbird-server dashboard proxy + ``` For upgrades from older versions (pre-v0.26.0), see the [Legacy upgrade notes](#legacy-self-hosting-with-zitadel-idp) below. @@ -69,6 +77,12 @@ docker compose pull management dashboard signal relay docker compose up -d --force-recreate management dashboard signal relay ``` +If you have the [Reverse Proxy](/manage/reverse-proxy) enabled, also pull and recreate the proxy: + +```bash +docker compose pull proxy && docker compose up -d --force-recreate proxy +``` + ## Get In Touch Feel free to ping us on [Slack](/slack-url) if you have any questions. diff --git a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx index fc52184c..de20eba1 100644 --- a/src/pages/selfhosted/migration/enable-reverse-proxy.mdx +++ b/src/pages/selfhosted/migration/enable-reverse-proxy.mdx @@ -184,6 +184,31 @@ The Traefik labels configure a **TCP router** that: The `HostSNI(*)` rule acts as a catch-all for any domain not matched by the existing NetBird HTTP routers. The `priority=1` ensures this TCP router only handles traffic that no other router claims. Any domain pointing to your server that isn't `netbird.example.com` will be forwarded to the proxy. +### Exposing L4 ports + +The Traefik configuration above only routes port 443 to the proxy container. HTTP and TLS services work over this port automatically (via SNI routing), but TCP and UDP services listen on dedicated ports that need to be exposed separately. + +If you plan to use L4 services (TCP or UDP mode), add `ports` entries directly to the `proxy` service in your `docker-compose.yml` for each port you want to expose. These ports should be mapped on the proxy container itself, not through Traefik, since routing them through Traefik would add an unnecessary extra hop: + +```yaml +proxy: + # ...existing configuration... + ports: + - "5432:5432/tcp" # Example: PostgreSQL + - "3306:3306/tcp" # Example: MySQL + - "5353:5353/udp" # Example: DNS +``` + +Each entry maps a host port to the same port inside the container. Add or remove entries as you create or delete L4 services. After changing the ports, apply with: + +```bash +docker compose up -d proxy +``` + + +You only need port mappings for TCP and UDP mode services. HTTP and TLS mode services are routed through port 443 via Traefik and do not require additional port entries. + + ### Step 4: Set up DNS records Create one DNS record pointing to the server running your NetBird stack - one for the base proxy domain and one wildcard for service subdomains: