Bring Your Own Proxy

Bring Your Own Proxy (BYOP) lets a NetBird account run its own reverse proxy on its own infrastructure. The proxy connects to NetBird's management service like any other proxy, but is bound to a single account: only that account's services route through it, and no other account on the same management instance can register against the same domain.

It is the option to choose when you want:

  • Full control over traffic — proxied traffic terminates on infrastructure you operate, not on shared proxy clusters managed by the platform.
  • Specific geographic placement — pick the region and provider you need (regulatory, latency, residency).
  • Your own TLS / domain — the proxy issues certificates directly via Let's Encrypt for a wildcard under a domain you own.

In the dashboard, BYOP proxies live under Reverse Proxy > Clusters and appear as account clusters. See Shared and account clusters for the full distinction.

Shared and account clusters

A cluster is a group of one or more proxy instances that serve the same apex domain (NB_PROXY_DOMAIN). Every service registers against exactly one cluster, and traffic to subdomain.cluster-apex is routed to any healthy proxy in that cluster.

NetBird recognises two cluster types, distinguished by the type field on the /api/reverse-proxies/clusters response and by the icon next to the cluster name in the dashboard:

Shared cluster (type: "shared")Account cluster (type: "account")
Who runs itNetBird (Cloud) or the operator of a self-hosted management instanceThe account itself (BYOP)
Who can use itEvery account on the management instanceOnly the account that registered it
Apex domainProvided by the platform (e.g. eu.proxy.netbird.io); subdomains are minted per serviceProvided by the account (e.g. proxy.company.com); the account owns the DNS
TLSManaged by the platformIssued by the proxy you run (ACME by default, or your own certs)
Registration tokenManagement-wide proxy tokenAccount-scoped proxy token (one per account)
Geographic placementWherever the platform runs proxiesWherever you choose to run the container
Reserved across the instanceYes — no account cluster can register against the same apexYes — once registered, the apex is unavailable to other accounts and to shared proxies
Visible to other accountsYes, as an available cluster in their service-creation flowNo — only the owning account sees it
Delete from dashboardNot allowedAllowed (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).

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.

How it works

A BYOP proxy is an instance of the same netbirdio/reverse-proxy Docker image used elsewhere, but registered with the management server through an account-scoped proxy access token. The token carries your account ID; the management server enforces it on every gRPC call from the proxy:

  • Only services from your account are streamed to the proxy.
  • The cluster address (your NB_PROXY_DOMAIN) is reserved across the management instance: no other account, and no management-wide self-hosted proxy on the same management, can register a proxy on the same domain.
  • Revoking the token disconnects all proxies registered with it within roughly one heartbeat interval (~60 seconds).
  • Deleting a self-hosted proxy from the dashboard removes its database record and hides the cluster from the API and dashboard. A proxy process that is still running keeps its existing gRPC stream open until it is stopped or its token is revoked, but it will no longer appear in the cluster list.

Once registered, your BYOP proxy:

  1. Receives a stream of service mappings (only services that target your cluster domain).
  2. Provisions Let's Encrypt certificates for each domain it serves (or uses static / wildcard certificates you mount in).
  3. Joins your NetBird mesh as embedded WireGuard peers (one per account — in BYOP, that's just yours) and forwards traffic to backend peers or network resources over the tunnel.

You can run multiple BYOP proxy instances with the same token and the same NB_PROXY_DOMAIN to form an HA cluster — DNS round-robin or your own load balancer in front, and management routes services to all connected proxies in the cluster.

Prerequisites

Before you start, make sure you have:

  • A NetBird account with Network Admin (or higher) access on a management instance that supports BYOP — the Services permission is required to create proxy tokens and manage account clusters.
  • A server with a public IP that can accept inbound TCP traffic on port 443 (clients connect here, and Let's Encrypt's default tls-alpn-01 challenge validates here). Port 80 is only needed if you switch the ACME challenge to http-01. For HA, repeat for every replica behind the same domain.
  • Docker installed and running on that server.
  • A domain you control that you can point at the server. You will configure two A records: proxy-domain and *.proxy-domain.

Setup walkthrough

NetBird's dashboard provides a three-step wizard that generates the proxy token, shows the DNS records to add, and emits a ready-to-run docker run command. You can also drive the same flow through the API — see Set up a BYOP proxy from the API.

Step 1: Open Clusters and start the wizard

Navigate to Reverse Proxy > Clusters in the NetBird dashboard. The table lists every cluster your account can reach — both the shared platform clusters and any account clusters you've already set up.

Click Setup Self-Hosted Cluster to open the wizard.

Clusters page in the dashboard with the Setup Self-Hosted Cluster button

Step 2: Choose your domain

In the Domain tab, enter the domain that this proxy cluster will be reachable on, e.g., proxy.company.com. This becomes the proxy's NB_PROXY_DOMAIN and the suffix of every public service URL hosted on it ({subdomain}.proxy.company.com).

Setup Cluster modal showing the Domain tab with the requirements callout

The wizard reminds you of the host requirements — public IP, Docker, ports 80 and 443 free. Click Continue to move to the DNS step.

Step 3: Configure DNS records

In the DNS Records tab, add the two A records shown in the table at your domain registrar:

TypeNameContent
Aproxy.company.comYour machine's public IP
CNAME*.proxy.company.comproxy.company.com

The wildcard record is required so that every service domain ({subdomain}.proxy.company.com) resolves to your proxy. If you run an HA cluster, point both records at all replicas (round-robin) or at the IP of a load balancer / floating IP that fronts them.

Setup Cluster modal showing the DNS Records tab with copyable A record entries

Click Continue to move to the install step.

Step 4: Run the proxy

Switching to the Run the Proxy tab automatically generates a one-time, account-scoped proxy token and embeds it into a ready-to-run docker run command:

Setup Cluster modal showing the Run the Proxy tab with the generated docker run command

docker run -d \
 -v /var/lib/certs:/certs \
 -e NB_PROXY_CERTIFICATE_DIRECTORY=/certs \
 -e NB_PROXY_ALLOW_INSECURE=true \
 -e NB_PROXY_MANAGEMENT_ADDRESS=https://api.netbird.io \
 -e NB_PROXY_ACME_CERTIFICATES=true \
 -e NB_PROXY_DOMAIN=proxy.company.com \
 -e NB_PROXY_LOG_LEVEL=info \
 -e NB_PROXY_TOKEN=nbx_... \
 -p 80:80 -p 443:443 \
 netbirdio/reverse-proxy:latest

The wizard substitutes NB_PROXY_MANAGEMENT_ADDRESS based on the dashboard's configured management endpoint — https://api.netbird.io for NetBird Cloud, or your own management URL on a self-hosted deployment. The example above shows the Cloud value; if you're on self-hosted you will see your URL there.

Run the command on your server. The container will:

  1. Connect to NetBird's management server (https://api.netbird.io for NetBird Cloud, or the management URL of your self-hosted deployment) over gRPC and authenticate with the token. The wizard fills this in based on the dashboard's configured management endpoint.
  2. Register itself as a proxy in your account's proxy.company.com cluster.
  3. Begin requesting Let's Encrypt certificates for each service hostname under that cluster.

Click Finish Setup to close the wizard.

Step 5: Verify the proxy is connected

Back on the Clusters page, the new account cluster appears once the proxy registers, with a count of connected proxies and an Online badge. A non-zero connected count means at least one replica is alive and exchanging mappings with management.

Clusters page showing a connected account cluster with one proxy

You can also check the proxy's own health probe — by default it binds to localhost:8080 on the proxy host, so run this on the box itself:

curl -s http://localhost:8080/healthz

Healthy output reports management_connected: true and initial_sync_complete: true. To probe from another host, override the bind address with NB_PROXY_HEALTH_ADDRESS=:8080 and publish the port from the container.

Use the proxy for services

Once the cluster is connected, your BYOP domain shows up in the service creation flow as a regular Cluster option in the domain picker.

  1. Go to Reverse Proxy > Services > Add Service.
  2. Choose a subdomain and pick your BYOP domain (proxy.company.com) as the base domain.
  3. Configure targets, authentication, and access restrictions as you would for any other reverse proxy service. See Reverse Proxy overview for service mode, target, and authentication details.

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.

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:

  • Registers itself with management as part of the same cluster.
  • Receives the full set of service mappings for the cluster.
  • Maintains its own WireGuard tunnels to backend peers.

For DNS, point both A records at all replica IPs (round-robin) or at a load balancer / floating IP that fronts them. For TLS, see Sharing certificates across replicas.

For broader operational guidance — token rotation, cert lock methods, monitoring — see Running Multiple Proxy Instances. The same operational patterns apply, with the caveat that BYOP cluster scope is your account, not the whole management instance.

TLS configuration

The Docker command produced by the wizard uses ACME (Let's Encrypt) with the tls-alpn-01 challenge by default. That mode needs only port 443 open and works without an additional HTTP listener.

Other modes are supported by the same image. To switch challenge type, supply your own certificates, or use a wildcard certificate, set the corresponding environment variables. The variables documented in TLS certificate configuration apply identically to BYOP — only the management endpoint and the account-scoped token make BYOP different from a management-wide self-hosted proxy.

The most common adjustments:

GoalVariable / value
Use Let's Encrypt with port 80 instead of port 443NB_PROXY_ACME_CHALLENGE_TYPE=http-01
Provide your own certificate and keyunset NB_PROXY_ACME_CERTIFICATES, mount cert + key into NB_PROXY_CERTIFICATE_DIRECTORY (defaults: tls.crt, tls.key)
Use a wildcard certificate for *.proxy.company.comNB_PROXY_WILDCARD_CERT_DIR=/certs/wildcard

Sharing certificates across replicas

When multiple replicas use ACME, share NB_PROXY_CERTIFICATE_DIRECTORY between them (e.g., a network volume) so they don't re-issue the same certificate from each replica and hit Let's Encrypt rate limits. The proxy uses a cross-replica lock to coordinate issuance — NB_PROXY_CERT_LOCK_METHOD defaults to auto, which detects the right backend; set it explicitly to flock for shared filesystems or k8s-lease for Kubernetes deployments if auto-detection picks the wrong one.

Set up a BYOP proxy from the API

If you prefer the API over the wizard, the flow is two calls plus the docker run:

1. Create an account-scoped proxy token. Replace <MANAGEMENT_URL> with https://api.netbird.io for NetBird Cloud, or with the management URL of your self-hosted deployment. Save the plain_token from the response — it's shown only this once.

curl -X POST <MANAGEMENT_URL>/api/reverse-proxies/proxy-tokens \
  -H "Authorization: Token <PAT>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "byop-eu-west",
    "expires_in": 0
  }'

expires_in is in seconds; 0 means never expires. Pick a meaningful name — it appears in the token list and is helpful when revoking.

2. Configure the two A records for your domain (see Step 3 above).

3. Run the proxy with the token from step 1:

docker run -d \
 -v /var/lib/certs:/certs \
 -e NB_PROXY_CERTIFICATE_DIRECTORY=/certs \
 -e NB_PROXY_MANAGEMENT_ADDRESS=<MANAGEMENT_URL> \
 -e NB_PROXY_ACME_CERTIFICATES=true \
 -e NB_PROXY_DOMAIN=proxy.company.com \
 -e NB_PROXY_TOKEN=<plain_token_from_step_1> \
 -p 80:80 -p 443:443 \
 netbirdio/reverse-proxy:latest

4. Verify with GET /api/reverse-proxies/clusters (BYOP clusters return "type": "account"; platform-managed clusters return "type": "shared") or check the Clusters page in the dashboard.

Manage proxies and tokens

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:

  • 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.

Manage tokens

Proxy tokens are independent of proxy registrations: one token can register many proxies (HA), and revoking the token disconnects all of them. You can list, create, and revoke tokens via the API (replace <MANAGEMENT_URL> with https://api.netbird.io for NetBird Cloud, or your self-hosted deployment's management URL):

# List tokens
curl <MANAGEMENT_URL>/api/reverse-proxies/proxy-tokens \
  -H "Authorization: Token <PAT>"

# Revoke a token
curl -X DELETE <MANAGEMENT_URL>/api/reverse-proxies/proxy-tokens/<tokenId> \
  -H "Authorization: Token <PAT>"

Within roughly one heartbeat interval (60 seconds) of a revoke, every proxy registered with that token loses its gRPC stream and its services stop being served. Restart the proxy with a new token to bring it back.

Troubleshooting

SymptomLikely causeFix
Proxy logs show Unauthenticated immediately after startWrong or missing NB_PROXY_TOKEN, or token revokedGenerate a new token in the dashboard or API and restart with the new value
Proxy logs show cluster address ... is already in useAnother account, or a management-wide self-hosted proxy on the same management, already owns this cluster domainPick a domain that no other account or management-wide proxy on this management is using — cluster domains are reserved across the management instance
Service stuck in certificate_pendingACME challenge cannot complete: ports blocked, DNS not propagated, or geo-blocking on validation trafficVerify both A records resolve correctly; ensure ports 80/443 are reachable from anywhere; switch to http-01 if tls-alpn-01 fails. See TLS-ALPN-01 requirements
Service stays in tunnel_not_createdProxy can reach management but cannot reach the target peer over WireGuardConfirm the target peer is online (netbird status) and policies allow connectivity from the proxy's embedded peer. The proxy creates one embedded peer per account on first service mapping
Proxy disconnects roughly one minute after startToken was revoked or expired (the heartbeat checks token validity every minute and tears down the gRPC stream when it fails)Generate a new token, restart the proxy
Setup Self-Hosted Cluster button greyed outAccount user lacks the services:create permissionAsk a Network Admin (or higher) to set up the cluster or grant the role

For deeper debugging, raise the log level to debug or trace (NB_PROXY_LOG_LEVEL=debug) and consult the proxy's /healthz endpoint.