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 > Self-Hosted Proxies.

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 self-hosted proxies.
  • 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 Self-Hosted Proxies and start the wizard

Navigate to Reverse Proxy > Self-Hosted Proxies in the NetBird dashboard. If your account has no self-hosted proxies yet, you'll see the get-started card; otherwise the table lists existing clusters.

Click Setup Proxy to open the wizard.

Self-Hosted Proxies page in the dashboard with the Setup Proxy 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 Proxy 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
A*.proxy.company.comYour machine's public IP

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 Proxy 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 Proxy 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 Self-Hosted Proxies page, the new cluster appears once the proxy registers, with a count of connected proxies. A non-zero connected count means at least one replica is alive and exchanging mappings with management.

Self-Hosted Proxies page showing a connected 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 carry self_hosted: true) or check the Self-Hosted Proxies page in the dashboard.

Manage proxies and tokens

Manage proxies

The Self-Hosted Proxies page lists each cluster and the number of currently connected proxies. The same data is available via GET /api/reverse-proxies/clusters — BYOP clusters carry the self_hosted: true flag. From the page you can:

  • Refresh to pull fresh status.
  • Delete a 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 a self-hosted proxy, delete the cluster 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 Proxy button greyed outAccount user lacks the services:create permissionAsk a Network Admin (or higher) to set up the proxy 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.