mirror of
https://github.com/netbirdio/docs.git
synced 2026-10-27 15:09:04 +01:00
docs: reorganize Use Cases navigation (#834)
* docs: consolidate scenario guides under /use-cases with redirects Move 11 pages: feature-nested use cases from manage/networks, manage/network-routes, manage/reverse-proxy, and the Kubernetes integration into /use-cases/remote-access, /use-cases/cloud, and /use-cases/security; the site-to-site decision page becomes /use-cases/remote-access; the MikroTik guide becomes an install guide at /get-started/install/mikrotik. Add one redirect per moved page and flatten existing redirect chains so every legacy URL resolves in a single hop. The deprecated Routes site-to-site recipe stays put. * docs: rebuild sidebar navigation for use-cases reorg Remove the four nested Use Cases sublists from Manage NetBird; keep the deprecated Routes recipe as a direct 'Site-to-Site (legacy)' link. Rebuild USE CASES with Remote Access, Cloud & Kubernetes, Security groups and a flat Homelab link. Add MikroTik to Get Started > Platforms. * docs: rebuild use-case index pages and refresh feature landing links Turn /use-cases into an "I want to..." scenario finder. Retitle the site-to-site decision page to Remote Access and point its links at the new sibling URLs. Add the Kubernetes service and private-proxy guides to the cloud and security indexes, refresh the homelab landing links, and update the Networks, Routes, Reverse Proxy, and Kubernetes landing pages to the new use-case URLs. * docs: update internal links to new use-case URLs Point cross-links across the docs at the consolidated /use-cases URLs. Links to the deprecated Routes site-to-site recipe and all image paths under public/docs-static are left unchanged. * docs: shorten sidebar label to Site-to-Site * docs: move Kubernetes into its own Use Cases section Pull the entire Kubernetes integration out of Manage > Integrations into a dedicated Kubernetes group under Use Cases at /use-cases/ kubernetes, and move the two Kubernetes cloud guides there too. Rename the Cloud group (was 'Cloud & Kubernetes'); Integrations keeps the MDM deployment pages. Add redirects for every moved page and flatten existing chains. * docs: drop 'NetBird on' prefix from cloud sidebar labels * docs: alphabetize Remote Access use cases in sidebar * ❯ add mikrotik to install index * docs: fix duplicated word in remote-access link label on TV install pages --------- Co-authored-by: Brandon Hopkins <brandon@techhut.tv>
This commit is contained in:
co-authored by
Brandon Hopkins
parent
8ae475c29c
commit
8824f4af97
@@ -21,7 +21,7 @@ This means the routing peer must be able to resolve the domain. If it can't —
|
||||
This covers ordinary name-to-IP lookups (**A/AAAA** records) for the resource's own domain. Two cases still need a nameserver configured on the client:
|
||||
|
||||
- **Routing Peer DNS Resolution is disabled.** It's on by default, but can be turned off per account. With it off, the client resolves the name itself instead of asking the routing peer — so point the client at your internal DNS with a nameserver (or its network adapter's DNS).
|
||||
- **Active Directory.** A domain-joined client always needs a nameserver (`corp.example.com` → the DC), no matter how this setting is configured — see [Active Directory & Windows File Shares](/manage/networks/use-cases/active-directory).
|
||||
- **Active Directory.** A domain-joined client always needs a nameserver (`corp.example.com` → the DC), no matter how this setting is configured — see [Active Directory & Windows File Shares](/use-cases/remote-access/active-directory).
|
||||
</Note>
|
||||
|
||||
To fix this, add the **routing peer's group** to the internal Nameserver's distribution groups — along with any client groups that resolve these names directly (Active Directory clients always do):
|
||||
@@ -161,7 +161,7 @@ Before deleting a primary nameserver, create a new primary first, or peers will
|
||||
Active Directory (AD) environments have specific DNS requirements because Domain Controllers (DCs) run their own DNS services and rely on DNS for core AD functionality like domain joins, authentication, and service discovery.
|
||||
|
||||
<Note>
|
||||
Setting up remote access to AD file shares, DFS, and domain login end to end? See the [Active Directory & Windows File Shares](/manage/networks/use-cases/active-directory) guide — it ties together the routing, DNS, and Kerberos pieces into a single setup. The sections below are the DNS reference behind it.
|
||||
Setting up remote access to AD file shares, DFS, and domain login end to end? See the [Active Directory & Windows File Shares](/use-cases/remote-access/active-directory) guide — it ties together the routing, DNS, and Kerberos pieces into a single setup. The sections below are the DNS reference behind it.
|
||||
</Note>
|
||||
|
||||
### Reaching a Domain Controller through a routing peer
|
||||
|
||||
@@ -470,7 +470,7 @@ A domain resource only resolves `A`/`AAAA` records. Active Directory also depend
|
||||
|
||||
**Solutions**:
|
||||
|
||||
- Add a **DNS nameserver** with match domain `corp.example.com` pointing at the DC's IP, distributed to your remote-users group — see [Active Directory & Windows File Shares → Give clients corp DNS](/manage/networks/use-cases/active-directory#step-5-give-clients-corp-dns).
|
||||
- Add a **DNS nameserver** with match domain `corp.example.com` pointing at the DC's IP, distributed to your remote-users group — see [Active Directory & Windows File Shares → Give clients corp DNS](/use-cases/remote-access/active-directory#step-5-give-clients-corp-dns).
|
||||
- Confirm the DC itself is reachable through the routing peer on the AD ports — see [Reaching a Domain Controller through a routing peer](/manage/dns/internal-dns-servers#reaching-a-domain-controller-through-a-routing-peer).
|
||||
|
||||
---
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
# API Server Proxy
|
||||
|
||||
Managing access to a Kubernetes cluster can be challenging. Security requirements may prohibit exposing the API server to the public internet. While integrations with existing authorization systems may be impossible. The NetBird API server proxy solves both the access and authorization problem in a single solution by exposing the API server through NetBirds network while using the NetBird identity to append permissions to the incoming request. All done without the need to store any credentials on the local machine.
|
||||
|
||||
## Deploying Proxy
|
||||
|
||||
The proxy needs a service account with impersonation permissions. This is required so that the correct identity can be appended to the request. These RBAC resources cannot be created by the operator as it would require the operator itself to have these elevated permissions.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: clusterproxy-prod
|
||||
namespace: netbird
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: clusterproxy-prod
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- users
|
||||
- groups
|
||||
verbs:
|
||||
- impersonate
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- userextras/*
|
||||
- uids
|
||||
verbs:
|
||||
- impersonate
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: clusterproxy-prod
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: clusterproxy-prod
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: clusterproxy-prod
|
||||
namespace: netbird
|
||||
```
|
||||
|
||||
We can create the cluster proxy once the RBAC resources have been created. The cluster will be accessible once the proxy pod is ready.
|
||||
|
||||
```yaml
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: ClusterProxy
|
||||
metadata:
|
||||
name: prod
|
||||
namespace: netbird
|
||||
spec:
|
||||
clusterName: prod
|
||||
serviceAccountName: clusterproxy-prod
|
||||
```
|
||||
|
||||
## Assigning Permissions
|
||||
|
||||
The proxy uses [user impersonation](https://kubernetes.io/docs/reference/access-authn-authz/user-impersonation/) to grant to each call based on the source of the request. The request to the API server is modified to include the NetBird users and groups the user is a member of. The group name can then be used in role bindings to assign permissions. In this example any NetBird users who is a member of the kubernetes-read group will get full read access to the cluster.
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: netbird-cluster-reader
|
||||
rules:
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: netbird-cluster-reader
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: kubernetes-read
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: netbird-cluster-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
## Accessing Cluster
|
||||
|
||||
The cluster can be found through the NetBird CLI.
|
||||
|
||||
```bash
|
||||
netbird kubernetes list
|
||||
```
|
||||
|
||||
All clusters that the user has access to will show up.
|
||||
|
||||
```bash
|
||||
Available Kubernetes clusters:
|
||||
|
||||
- Name: prod
|
||||
FQDN: prod.netbird-kubeapi-proxy.netbird.cloud.
|
||||
Version: v1.35.0
|
||||
```
|
||||
|
||||
Configuration to access the cluster can then be appended to the local kubeconfig file.
|
||||
|
||||
```bash
|
||||
netbird kubernetes write-kubeconfig prod
|
||||
```
|
||||
|
||||
We should not be able to list all pods in the cluster.
|
||||
|
||||
```bash
|
||||
kubectl --context prod get pods -A
|
||||
```
|
||||
@@ -1,47 +0,0 @@
|
||||
# Client Sidecar
|
||||
|
||||
In certain situations we may want to have a pod act like a peer in the Netbird network instead of exposing it through a routing peer. In these cases a Netbird client container has to be added as a sidecar to the pod.
|
||||
|
||||
Sidecars are appended to pods when created if they match the selector of a sidecar profile. A sidecar profile defines the configuration of the sidecar, like the setup key to be used along with other parameters. An empty selector will match with all pods in the namespace. The sidecar profile needs to be created first before any pod is created.
|
||||
|
||||
```yaml
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: SetupKey
|
||||
metadata:
|
||||
name: sidecar
|
||||
namespace: default
|
||||
spec:
|
||||
name: sidecar
|
||||
ephemeral: true
|
||||
---
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: SidecarProfile
|
||||
metadata:
|
||||
name: test
|
||||
namespace: default
|
||||
spec:
|
||||
setupKeyRef:
|
||||
name: sidecar
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: ubuntu
|
||||
```
|
||||
|
||||
When a pod matching the selector is created it will receive a netbird sidecar container.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: ubuntu
|
||||
namespace: default
|
||||
labels:
|
||||
app: ubuntu
|
||||
spec:
|
||||
containers:
|
||||
- name: ubuntu
|
||||
image: ubuntu:latest
|
||||
command: ["sleep", "infinity"]
|
||||
```
|
||||
|
||||
Once both containers have started the pod should show up like a peer in the Netbird dashboard.
|
||||
@@ -1,253 +0,0 @@
|
||||
# Kubernetes Gateway API Integration <Badge status="experimental" text="Beta" />
|
||||
|
||||
The NetBird Kubernetes operator supports the [Gateway API](https://gateway-api.sigs.k8s.io/) as an alternative to annotation-based service exposure. Using standard Gateway API resources, you can:
|
||||
|
||||
- **Expose services publicly** via reverse proxy using `HTTPRoute` resources with the public gateway class
|
||||
- **Expose services privately** to your NetBird network using `TCPRoute` resources with the private gateway class
|
||||
|
||||
The operator watches for these Gateway API resources and automatically creates the corresponding [Networks and Resources](/manage/networks) in your NetBird account.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have the following:
|
||||
|
||||
- **Helm** version 3+ (recommended)
|
||||
- **kubectl** version v1.11.3+
|
||||
- Access to a **Kubernetes** v1.11.3+ cluster
|
||||
- **Cert Manager** (recommended) — for secure communication between the k8s API and the operator
|
||||
- A **NetBird API token** — you can create a PAT by following the steps [here](/manage/public-api#creating-a-service-user)
|
||||
|
||||
## Installation
|
||||
|
||||
### Step 1: Add the Helm repository
|
||||
|
||||
```shell
|
||||
helm repo add netbirdio https://netbirdio.github.io/helms
|
||||
```
|
||||
|
||||
### Step 2: Install Cert Manager
|
||||
|
||||
This is recommended for the k8s API to communicate securely with the NetBird operator.
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml
|
||||
```
|
||||
|
||||
### Step 3: Install the Gateway API CRDs
|
||||
|
||||
The operator requires the experimental Gateway API CRDs to be installed in your cluster.
|
||||
|
||||
```shell
|
||||
kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/experimental-install.yaml
|
||||
```
|
||||
|
||||
### Step 4: Create the NetBird API secret
|
||||
|
||||
Create a namespace for the operator and store your API token as a Kubernetes secret.
|
||||
|
||||
```shell
|
||||
kubectl create namespace netbird
|
||||
kubectl -n netbird create secret generic netbird-mgmt-api-key --from-literal=NB_API_KEY=$(cat ~/nb-pat.secret)
|
||||
```
|
||||
|
||||
<Note>
|
||||
Replace `~/nb-pat.secret` with the path to your NetBird API key.
|
||||
</Note>
|
||||
|
||||
### Step 5: Install the operator
|
||||
|
||||
<Warning>
|
||||
The operator version 0.3.0-rc.2 is subject to breaking changes. Values and behavior may change in future releases.
|
||||
</Warning>
|
||||
|
||||
```shell
|
||||
helm upgrade --install kubernetes-operator netbirdio/kubernetes-operator \
|
||||
--namespace netbird \
|
||||
--create-namespace \
|
||||
--version 0.3.0-rc.2 \
|
||||
-f - <<EOF
|
||||
|
||||
gatewayAPI:
|
||||
enabled: true
|
||||
|
||||
webhook:
|
||||
enableCertManager: false
|
||||
|
||||
netbirdAPI:
|
||||
keyFromSecret:
|
||||
name: "netbird-mgmt-api-key"
|
||||
key: "NB_API_KEY"
|
||||
|
||||
EOF
|
||||
```
|
||||
|
||||
### Step 6: Verify the installation
|
||||
|
||||
```bash
|
||||
kubectl -n netbird get pods
|
||||
# Expected: netbird-operator-kubernetes-operator-xxxxx 1/1 Running
|
||||
```
|
||||
|
||||
## Configure Routing Peers and Gateways
|
||||
|
||||
Once the operator is running, deploy the routing peers and gateway resources. The operator supports two gateway classes:
|
||||
|
||||
- **`netbird-public`** — exposes services through a reverse proxy, making them accessible via a public hostname using `HTTPRoute` resources
|
||||
- **`netbird-private`** — exposes services as private network resources, accessible only to peers within your NetBird network using `TCPRoute` resources
|
||||
|
||||
```bash
|
||||
cat <<EOF | kubectl apply -f -
|
||||
|
||||
apiVersion: netbird.io/v1
|
||||
kind: NBRoutingPeer
|
||||
metadata:
|
||||
name: netbird
|
||||
namespace: netbird
|
||||
spec: {}
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: private
|
||||
namespace: netbird
|
||||
spec:
|
||||
gatewayClassName: netbird-private
|
||||
listeners:
|
||||
- protocol: gateway.netbird.io/NBRoutingPeer
|
||||
name: netbird
|
||||
port: 1
|
||||
---
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: public
|
||||
namespace: netbird
|
||||
spec:
|
||||
gatewayClassName: netbird-public
|
||||
listeners:
|
||||
- protocol: gateway.netbird.io/NBRoutingPeer
|
||||
name: netbird
|
||||
port: 1
|
||||
|
||||
EOF
|
||||
```
|
||||
|
||||
## Expose Services via Reverse Proxy (Public Gateway)
|
||||
|
||||
Use `HTTPRoute` resources with the **public** gateway to expose Kubernetes services through a reverse proxy. You can optionally add the `hostnames` field to make the service accessible via a specific domain.
|
||||
|
||||
<Note>
|
||||
If using a custom hostname, make sure that the domain name is properly configured in your DNS settings.
|
||||
</Note>
|
||||
|
||||
The following example deploys a demo application and creates an `HTTPRoute` with a custom hostname pointing to the public gateway:
|
||||
|
||||
```bash
|
||||
export DEPLOYMENT_NAME=demo-nb-k8s; export DEPLOYMENT_IMAGE=ghcr.io/netbirdio/kubernetes-demo; cat <<EOF | kubectl apply -f -
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: $DEPLOYMENT_NAME
|
||||
namespace: default
|
||||
labels:
|
||||
app: $DEPLOYMENT_NAME
|
||||
spec:
|
||||
hostnames:
|
||||
# Optional: omit this field if you don't want to expose this through the reverse proxy
|
||||
- demo-nb-k8s.eu1.netbird.services
|
||||
parentRefs:
|
||||
- name: public
|
||||
namespace: netbird
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: $DEPLOYMENT_NAME
|
||||
port: 80
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: $DEPLOYMENT_NAME
|
||||
namespace: default
|
||||
labels:
|
||||
app: $DEPLOYMENT_NAME
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: $DEPLOYMENT_NAME
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: $DEPLOYMENT_NAME
|
||||
spec:
|
||||
containers:
|
||||
- image: $DEPLOYMENT_IMAGE
|
||||
imagePullPolicy: Always
|
||||
name: demo
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: $DEPLOYMENT_NAME
|
||||
namespace: default
|
||||
labels:
|
||||
app: $DEPLOYMENT_NAME
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: $DEPLOYMENT_NAME
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
EOF
|
||||
```
|
||||
|
||||
## Expose Private Resources (Private Gateway)
|
||||
|
||||
Use `TCPRoute` resources with the **private** gateway to expose services as private network resources, accessible only to peers within your NetBird network.
|
||||
|
||||
The following example exposes the Kubernetes API server to your NetBird peers:
|
||||
|
||||
```bash
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: gateway.networking.k8s.io/v1alpha2
|
||||
kind: TCPRoute
|
||||
metadata:
|
||||
name: kubernetes
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: private
|
||||
namespace: netbird
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: kubernetes
|
||||
port: 443
|
||||
EOF
|
||||
```
|
||||
|
||||
## Work in progress features
|
||||
|
||||
We know the operator is not yet feature complete, but we thought you would like to hear that we're working on:
|
||||
- ACL policy attachment
|
||||
- Reverse Proxy authentication configuration
|
||||
- Multi-cluster support
|
||||
- Kubernetes API RBAC support
|
||||
|
||||
## Get started
|
||||
<div style={{textAlign: "center"}}>
|
||||
<Button name="button" className="button-5" onClick={() => window.open("https://netbird.io/pricing")}>Use NetBird</Button>
|
||||
</div>
|
||||
|
||||
- Make sure to [star us on GitHub](https://github.com/netbirdio/netbird)
|
||||
- Follow us [on X](https://x.com/netbird)
|
||||
- Join our [Slack Channel](/slack-url)
|
||||
- NetBird [latest release](https://github.com/netbirdio/netbird/releases) on GitHub
|
||||
@@ -1,71 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
Accessing private Kubernetes clusters can be challenging, especially when connecting from remote locations or having multiple clusters to manage. NetBird Kubernetes operator simplifies this process by enabling secure access to your Kubernetes clusters using custom resource configurations and annotations to expose your cluster and services in your NetBird network.
|
||||
|
||||
The NetBird Kubernetes operator automatically creates [Networks and Resources](/manage/networks) in your NetBird account, allowing you to seamlessly access your Kubernetes services and control plane from your NetBird network.
|
||||
|
||||
<Note>
|
||||
For the mental model — see [How Routing Peers Work — Requirements](/manage/networks/how-routing-peers-work#requirements).
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Access to a Kubernetes cluster.
|
||||
- Kubectl and Helm installed locally.
|
||||
|
||||
## Steps
|
||||
|
||||
Install cert-manager, it is recommended so the Kubernetes API can communicate with the operator's admission webhooks. Skip this step if you already have cert-manager installed.
|
||||
|
||||
```shell
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml
|
||||
```
|
||||
|
||||
Create the NetBird namespace and API secret. The operator needs a NetBird personal access token to authenticate with the NetBird Management API. You can create a PAT by following the steps [here](/manage/public-api#creating-a-service-user).
|
||||
|
||||
```shell
|
||||
kubectl create namespace netbird
|
||||
kubectl -n netbird create secret generic netbird-mgmt-api-key --from-literal=NB_API_KEY=${NB_API_KEY}
|
||||
```
|
||||
|
||||
Install the NetBird operator.
|
||||
|
||||
```shell
|
||||
helm upgrade --install --create-namespace -n netbird netbird-operator oci://ghcr.io/netbirdio/helm-charts/netbird-operator
|
||||
```
|
||||
|
||||
Verify the installation by checking the operator pod.
|
||||
|
||||
```shell
|
||||
kubectl get pods -n netbird
|
||||
```
|
||||
|
||||
All pods should be in a `Running` state before continuing.
|
||||
|
||||
```shell
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
netbird-operator-b74984867-d68c8 1/1 Running 0 98s
|
||||
```
|
||||
|
||||
## Choosing a pattern
|
||||
|
||||
The operator supports several ways to connect a cluster, and they answer **different questions** rather than competing with each other. Pick by **what you're exposing** and **whether each workload needs its own identity**.
|
||||
|
||||
| Pattern | Exposes | Identity | Reach it via | Best for |
|
||||
|---|---|---|---|---|
|
||||
| [NetworkRouter](/manage/integrations/kubernetes/routing-peer) | a `ClusterIP` Service | a shared routing peer | a DNS name in the NetworkRouter's zone (`service.namespace.<zone>`) | stable internal services (databases, APIs) that many peers reach |
|
||||
| [Client Sidecar](/manage/integrations/kubernetes/client-sidecar) | the pod itself | the pod becomes its own peer | the pod's overlay IP | workloads that need their own identity or per-pod access rules (ephemeral CI jobs, per-pod audit) |
|
||||
| [API Server Proxy](/manage/integrations/kubernetes/api-server-proxy) | the Kubernetes API | your NetBird user | `netbird kubernetes` + `kubectl` | operating remote clusters with `kubectl` |
|
||||
| [Gateway API](/manage/integrations/kubernetes/gateway-api) <Badge status="experimental" text="Beta" /> | Services via Gateway CRDs | a gateway routing peer | route hostname / overlay | teams standardizing on Gateway API CRDs |
|
||||
|
||||
### Rules of thumb
|
||||
|
||||
- **Default to a routing peer** for "let my peers reach a service in this cluster." One routing peer fronts many services and is the cheapest to operate — see the [Route to a Kubernetes service](/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service) how-to, including how to run it highly available.
|
||||
- **Reach for a client sidecar** only when per-pod identity matters. The pod becomes a first-class peer: it can be reached directly *and* originate connections out onto the NetBird network as itself. That's why a sidecar — not a routing peer — is the answer when a workload needs to *initiate* traffic onto the overlay. The cost is one peer per pod, so it's more to manage than a shared gateway.
|
||||
- **A routing peer exposes in-cluster services to your peers; it does not give other pods in the cluster a path out onto the overlay.** If an in-cluster workload needs to reach the NetBird network, give that pod a sidecar.
|
||||
- **The API Server Proxy is orthogonal** — it's about *operating* the cluster, not reaching the apps inside it. Combine it with any of the others.
|
||||
- **Gateway API is the future-standard surface but still Beta** — prefer the routing peer or sidecar for anything you depend on today.
|
||||
|
||||
<Note>
|
||||
NetBird is deny-by-default and the operator does **not** write your access policies. Whichever pattern you choose, put your peers in a dedicated group (never `All`) and create a policy that allows the access you want.
|
||||
</Note>
|
||||
@@ -1,86 +0,0 @@
|
||||
# Routing Peer
|
||||
|
||||
The operator exposes Kubernetes services to your NetBird network by combining two resources, a `NetworkRouter` and a `NetworkResource`.
|
||||
|
||||
## NetworkRouter
|
||||
|
||||
A `NetworkRouter` creates a network in NetBird and deploys routing peer pods in the cluster. These pods are configured as routing peers for the network, handling traffic between NetBird clients and services running in the cluster.
|
||||
|
||||
Before creating a `NetworkRouter`, you must first create a custom DNS zone in the [NetBird dashboard](/manage/dns/custom-zones). The DNS zone must exist before the operator can register it.
|
||||
|
||||
```yaml
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: NetworkRouter
|
||||
metadata:
|
||||
name: prod
|
||||
namespace: netbird
|
||||
spec:
|
||||
dnsZoneRef:
|
||||
name: prod.company.internal
|
||||
```
|
||||
|
||||
## NetworkResource
|
||||
|
||||
A `NetworkResource` exposes a Kubernetes service in NetBird by creating a matching resource in the routers network. The cluster IP of the service will be used as the resource IP. A record in the routers zone will also be created using the name and namespace of the service. The following example creates an nignx deployment and exposes the service with the record `nginx.default.prod.company.internal`.
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: nginx
|
||||
---
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: NetworkResource
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
spec:
|
||||
networkRouterRef:
|
||||
name: prod
|
||||
namespace: netbird
|
||||
serviceRef:
|
||||
name: nginx
|
||||
groups:
|
||||
- name: All
|
||||
```
|
||||
|
||||
Members of the `All` NetBird group can now reach the nginx service at `nginx.default.prod.company.internal` through the NetBird network.
|
||||
@@ -1,202 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Route to a Kubernetes service with high availability
|
||||
|
||||
This guide walks the whole journey: create the NetBird-side pieces the operator doesn't make (a custom DNS zone, groups, an access policy), deploy a redundant pool of routing peers, expose an in-cluster Service as a NetBird resource, and reach it by name from a NetBird client. Because the routing peers run as a high-availability pool, access keeps working when a routing-peer pod or a node fails.
|
||||
|
||||
## What you'll achieve
|
||||
|
||||
A NetBird client (for example, your laptop) reaches a private Kubernetes `ClusterIP` Service by a stable DNS name, with traffic flowing through a pool of routing-peer pods spread across your nodes. Lose a pod or a node and clients fail over automatically to a healthy peer.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/topology.svg" alt="A NetBird client reaching a Kubernetes service through three routing-peer pods, one per node" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kubernetes cluster (multiple nodes recommended, so routing peers can spread across them).
|
||||
- The NetBird operator installed — see [Getting Started](/manage/integrations/kubernetes).
|
||||
- A NetBird account and a [Personal Access Token](/manage/public-api#creating-a-service-user).
|
||||
- A NetBird client (the device that will reach the service) enrolled in your account.
|
||||
|
||||
In this guide the example objects are named `k8s.company.internal` (DNS zone), `kubernetes-clients` / `kubernetes-services` (groups), `kubernetes` (the network), and `nginx` (the Service). Substitute your own.
|
||||
|
||||
## Step 1: Create a custom DNS zone
|
||||
|
||||
The operator publishes each exposed Service as a DNS record inside a custom zone, so clients reach it by name instead of by its (ephemeral) ClusterIP. The zone must exist **before** you deploy the routing peers.
|
||||
|
||||
In the dashboard, go to **DNS > Zones > Add Zone**:
|
||||
|
||||
- **Name**: `k8s.company.internal`
|
||||
- **Distribution Groups**: `kubernetes-clients` — only peers in these groups can resolve the zone's records.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/01-dns-zone.png" alt="The k8s.company.internal custom DNS zone, distributed to the kubernetes-clients group, with the operator-created nginx record" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
<Note>
|
||||
Create only the zone — **leave its records empty**. You don't enter a hostname, IP, or TTL here. When you expose a Service in [Step 4](#step-4-expose-your-service), the operator automatically adds the `A` record (named `<service>.<namespace>.<zone>`, e.g. `nginx.default.k8s.company.internal`, pointing at the Service's ClusterIP, with a 5-minute TTL) — that's the record shown above.
|
||||
</Note>
|
||||
|
||||
See [Custom Zones](/manage/dns/custom-zones) for details.
|
||||
|
||||
## Step 2: Create groups and an access policy
|
||||
|
||||
NetBird is deny-by-default: nothing is reachable until a policy allows it, and the operator does **not** create groups or policies for you. Set up two groups and one policy under **Access Control**.
|
||||
|
||||
Create the groups via **Access Control > Groups**:
|
||||
|
||||
- `kubernetes-clients` — the peers that should reach your services (put your client device in it).
|
||||
- `kubernetes-services` — the destination group the exposed Services will be placed in.
|
||||
|
||||
Then create a policy via **Access Control > Policies > Add policy**:
|
||||
|
||||
- **Name**: `kubernetes-access`
|
||||
- **Source**: `kubernetes-clients`
|
||||
- **Destination**: `kubernetes-services`
|
||||
- **Protocol/Ports**: `TCP` `80` (match your Service's port)
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/02-access-policy.png" alt="The kubernetes-access policy allowing kubernetes-clients to reach kubernetes-services over TCP 80" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
See [Manage network access](/manage/access-control/manage-network-access).
|
||||
|
||||
<Note>
|
||||
Create the group **and** the policy before the `NetworkResource` in Step 4. Until both exist, traffic is denied even though DNS resolves.
|
||||
</Note>
|
||||
|
||||
## Step 3: Deploy the routing peers (HA)
|
||||
|
||||
A `NetworkRouter` creates a NetBird network and deploys routing-peer pods. Set `spec.workloadOverride.replicas` to run a redundant pool:
|
||||
|
||||
```yaml
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: NetworkRouter
|
||||
metadata:
|
||||
name: kubernetes
|
||||
namespace: netbird
|
||||
spec:
|
||||
dnsZoneRef:
|
||||
name: k8s.company.internal
|
||||
workloadOverride:
|
||||
replicas: 3
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl apply -f networkrouter.yaml
|
||||
```
|
||||
|
||||
The operator registers all replicas in a single routing-peer group at one metric, so each client connects through its lowest-latency peer and fails over automatically if that peer becomes unreachable (the equal-metric behavior in [How Routing Peers Work — High availability](/manage/networks/how-routing-peers-work#high-availability)). When `replicas > 1`, it also creates a **PodDisruptionBudget** with `maxUnavailable: 1`, so node drains and rolling updates never take down more than one routing peer at a time.
|
||||
|
||||
<Note>
|
||||
The operator already defaults to **3** replicas — set the field explicitly to be intentional, or raise it for more redundancy. See the [Routing Peer](/manage/integrations/kubernetes/routing-peer) page for the full `NetworkRouter` reference.
|
||||
</Note>
|
||||
|
||||
On a multi-node cluster, the operator spreads these replicas across nodes by default, so you already have node-level high availability: a node failure takes out only one routing peer and clients fail over to the rest.
|
||||
|
||||
## Step 4: Expose your Service
|
||||
|
||||
A `NetworkResource` maps a Kubernetes `ClusterIP` Service to a NetBird resource and creates a DNS record for it in the router's zone. Place it in the `kubernetes-services` group from Step 2:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
labels: { app: nginx }
|
||||
spec:
|
||||
replicas: 1
|
||||
selector: { matchLabels: { app: nginx } }
|
||||
template:
|
||||
metadata: { labels: { app: nginx } }
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:stable
|
||||
ports: [{ containerPort: 80 }]
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector: { app: nginx }
|
||||
ports:
|
||||
- { name: http, port: 80, targetPort: 80, protocol: TCP }
|
||||
---
|
||||
apiVersion: netbird.io/v1alpha1
|
||||
kind: NetworkResource
|
||||
metadata:
|
||||
name: nginx
|
||||
namespace: default
|
||||
spec:
|
||||
networkRouterRef:
|
||||
name: kubernetes
|
||||
namespace: netbird
|
||||
serviceRef:
|
||||
name: nginx
|
||||
groups:
|
||||
- name: kubernetes-services
|
||||
```
|
||||
|
||||
The Service must be type `ClusterIP`. The operator creates the record `nginx.default.k8s.company.internal` (`<service>.<namespace>.<zone>`) pointing at the Service's ClusterIP. The `kubernetes` network now shows its routing peers and the resource:
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/03-network.png" alt="The kubernetes network with its routing peers and the nginx resource" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 5: Verify and test failover
|
||||
|
||||
Confirm the routing-peer pods are running, spread across nodes, and protected by a PodDisruptionBudget:
|
||||
|
||||
```shell
|
||||
kubectl -n netbird get pods -l app.kubernetes.io/name=networkrouter -o wide
|
||||
kubectl -n netbird get pdb
|
||||
```
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/04-pods-across-nodes.png" alt="kubectl get pods -o wide showing the routing peers on different nodes" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
From a NetBird client in `kubernetes-clients`, resolve and reach the service:
|
||||
|
||||
```shell
|
||||
curl http://nginx.default.k8s.company.internal/
|
||||
```
|
||||
|
||||
Then delete one routing-peer pod (or drain its node) while curling in a loop — the connection keeps working as another peer takes over, and the Deployment reschedules the missing pod:
|
||||
|
||||
```shell
|
||||
kubectl -n netbird delete pod <routing-peer-pod>
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Routing Peer](/manage/integrations/kubernetes/routing-peer) — the `NetworkRouter` / `NetworkResource` reference.
|
||||
- [How Routing Peers Work](/manage/networks/how-routing-peers-work) — failover, metrics, and access control.
|
||||
|
||||
## Appendix: Friendly DNS names
|
||||
|
||||
Each `NetworkResource` is published at `<service>.<namespace>.<zone>` — here, `nginx.default.k8s.company.internal`. The operator always uses this form and it can't be customized on the `NetworkResource`.
|
||||
|
||||
To expose a service under a cleaner name, add a **CNAME** in a [custom DNS zone](/manage/dns/custom-zones) pointing at the operator's record:
|
||||
|
||||
```text
|
||||
app.k8s.company.internal CNAME nginx.default.k8s.company.internal
|
||||
```
|
||||
|
||||
In the dashboard, that's **DNS > Zones >** the zone's **Add** button: a `CNAME` record with hostname `app` and the operator's record as the target.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/integrations/kubernetes/use-cases/route-to-a-kubernetes-service/friendly-dns-cname.png" alt="Adding a CNAME record with hostname app targeting nginx.default.k8s.company.internal in the k8s.company.internal zone" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
Because it targets the operator-managed record, the alias keeps resolving if the service's ClusterIP changes. A static `A` record straight to the ClusterIP also works, but it goes stale when the ClusterIP changes — prefer the CNAME.
|
||||
|
||||
<Note>
|
||||
The friendly name is only a DNS alias — traffic still routes through the `NetworkResource`, so keep it in place. NetBird serves only the specific records you add to a zone; other names under the same domain keep resolving through your existing DNS, so reusing a real internal domain is safe — just avoid a name that already exists in your corporate DNS. These manual records are not managed by the operator, so you maintain them yourself.
|
||||
</Note>
|
||||
@@ -4,7 +4,7 @@ import { Tiles } from '@/components/Tiles'
|
||||
# Routes
|
||||
|
||||
<Warning>
|
||||
Routes are deprecated. Every use case except [exit nodes](/manage/network-routes/use-cases/exit-nodes) has moved to [Networks](/manage/networks). Use Networks for all new configurations. For a side-by-side comparison of the two models, see [How Routing Peers Work](/manage/networks/how-routing-peers-work).
|
||||
Routes are deprecated. Every use case except [exit nodes](/use-cases/remote-access/exit-nodes) has moved to [Networks](/manage/networks). Use Networks for all new configurations. For a side-by-side comparison of the two models, see [How Routing Peers Work](/manage/networks/how-routing-peers-work).
|
||||
</Warning>
|
||||
|
||||
Routes let you route traffic from NetBird peers to private networks without installing the NetBird client on every device. A routing peer forwards packets between your NetBird mesh network and your internal networks (LANs, VPCs, data centers).
|
||||
@@ -314,15 +314,15 @@ To prevent permission overflow, use dedicated Routing Peers for Routes and never
|
||||
</Note>
|
||||
|
||||
<Tiles
|
||||
title="Use Cases"
|
||||
title="Guides"
|
||||
items={[
|
||||
{
|
||||
href: '/manage/network-routes/use-cases/site-to-site',
|
||||
name: 'Site-to-Site',
|
||||
name: 'Site-to-Site (legacy)',
|
||||
description: 'Connect two networks through routing peers at each end',
|
||||
},
|
||||
{
|
||||
href: '/manage/network-routes/use-cases/exit-nodes',
|
||||
href: '/use-cases/remote-access/exit-nodes',
|
||||
name: 'Exit Nodes',
|
||||
description: 'Route all internet traffic through a specific peer',
|
||||
},
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
# Configuring Exit Nodes for Internet Traffic
|
||||
|
||||
Exit nodes route all internet-bound traffic from your devices through a designated routing peer. This guide explains how to configure default routes for internet traffic.
|
||||
|
||||
<Note>
|
||||
This feature requires NetBird version 0.27.0 or later.
|
||||
</Note>
|
||||
|
||||
## Concepts
|
||||
|
||||
### Default Routes
|
||||
|
||||
A default route (`0.0.0.0/0` for IPv4) directs all internet traffic through a designated routing peer.
|
||||
|
||||
When [IPv6 overlay addressing](#ipv6-support) is enabled for the peer, the management server automatically creates a matching `::/0` route so that both IPv4 and IPv6 internet traffic flow through the exit node. Peers without IPv6 enabled have their IPv6 traffic blocked to prevent leakage.
|
||||
|
||||
### Routing Peer
|
||||
|
||||
The routing peer acts as the exit node for internet traffic. It applies masquerading so that traffic appears to originate from the routing peer's public IP address.
|
||||
|
||||
<Note>
|
||||
For the mental model — see [How Routing Peers Work — Exit node mode](/manage/networks/how-routing-peers-work#exit-node-mode).
|
||||
</Note>
|
||||
|
||||
### Distribution Groups
|
||||
|
||||
Peers in the distribution groups send their internet traffic through the routing peer once it connects.
|
||||
|
||||
<Note>
|
||||
The minimum access policy required for peers to use an exit node is **Users** (source) → **Routing Peer** (destination) over **ICMP**. Ensure a policy with this configuration exists for the distribution groups assigned to the exit node route.
|
||||
</Note>
|
||||
|
||||
### Exit Node Selection and Auto Apply
|
||||
|
||||
Administrators configure exit nodes from the dashboard and can enable **Auto Apply** to have clients automatically use the exit node.
|
||||
|
||||
- **Auto Apply:** When enabled, clients automatically use the exit node. Users can still disable it manually on their device.
|
||||
- **Client override:** If a user selects or deselects an exit node on their device, that choice takes precedence over the server configuration.
|
||||
|
||||
<Note>
|
||||
The client user's explicit selection or deselection always takes precedence on that device.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
Auto Apply requires NetBird client version 0.55.0 or later.
|
||||
</Note>
|
||||
|
||||
### Existing Exit Node Routes
|
||||
|
||||
Exit node routes created before the Auto Apply feature was introduced are treated as having Auto Apply enabled. This preserves the previous behavior where exit nodes were applied automatically.
|
||||
|
||||
Clients running v0.55.0 or later auto-apply these routes unless the user has explicitly selected or deselected an exit node. Administrators can change the Auto Apply setting at any time.
|
||||
|
||||
## Configuration Steps
|
||||
|
||||
### 1. Open the Servers list
|
||||
|
||||
Navigate to the NetBird dashboard and open **Peers** (exit nodes are typically unattended machines like a VPS, router, or always-on host).
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/network-routes/use-cases/exit-nodes/netbird-peers.png" alt="Dashboard peers view" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
### 2. Select the Routing Peer
|
||||
|
||||
Choose the peer that will serve as your exit node.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/network-routes/use-cases/exit-nodes/netbird-peers-routing-peer.png" alt="Routing peer selection" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
### 3. Configure the Exit Node
|
||||
|
||||
Click **Add Exit Node**. In the dialog, assign one or more distribution groups to specify which peers should use this exit node.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/network-routes/use-cases/exit-nodes/netbird-peers-add-exit-node.png" alt="Add exit node dialog" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
To make the exit node available without automatic activation, disable **Auto Apply**. Users can then enable it manually.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/network-routes/use-cases/exit-nodes/exit-node-auto-apply.png" alt="Auto Apply option" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
Click **Add Exit Node** to complete the configuration. Masquerading is enabled by default.
|
||||
|
||||
### 4. Verify the Configuration
|
||||
|
||||
Check the peer view to confirm the routing peer is marked as an exit node.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/network-routes/use-cases/exit-nodes/netbird-peers-routing-peer-exit-node.png" alt="Exit node confirmation" className="imagewrapper-big"/>
|
||||
</p>
|
||||
|
||||
### 5. Configure DNS
|
||||
|
||||
Add a DNS server with the match domain set to `ALL`. Local DNS servers may not be accessible from the routing peer, and this also prevents DNS-based location leaks.
|
||||
|
||||
See [Manage DNS in your network](/manage/dns) for details.
|
||||
|
||||
## IPv6 Support
|
||||
|
||||
<Note>
|
||||
IPv6 overlay addressing requires NetBird v0.68.0 or later on both the routing peer and the clients.
|
||||
</Note>
|
||||
|
||||
When IPv6 is enabled in your account settings and the exit node peer supports it, the management server automatically generates a `::/0` route alongside the `0.0.0.0/0` route. No additional configuration is needed.
|
||||
|
||||
For peers that do not have IPv6 enabled (older clients, or accounts with IPv6 disabled), IPv6 traffic is blocked at the tunnel interface to prevent unintentional leakage through the exit node.
|
||||
|
||||
You can disable IPv6 on individual clients with the `--disable-ipv6` flag:
|
||||
|
||||
```bash
|
||||
netbird up --disable-ipv6
|
||||
```
|
||||
|
||||
See [IPv6 Overlay Addressing](/manage/settings/ipv6) for more details on enabling IPv6 for your account.
|
||||
|
||||
## High Availability
|
||||
|
||||
Exit nodes support high availability configurations. See [Creating Highly Available Routes](/manage/network-routes#creating-highly-available-routes) for more information.
|
||||
@@ -5,7 +5,7 @@ import { Note, Warning } from '@/components/mdx'
|
||||
Site-to-Site connects two networks through routing peers at each end. Neither end-device needs NetBird installed — the routing peers forward traffic across the NetBird tunnel.
|
||||
|
||||
<Warning>
|
||||
Routes are deprecated. For new site-to-site setups, use [Networks Site-to-Site](/manage/networks/use-cases/site-to-site) instead — it has per-Resource access control and is the actively developed system.
|
||||
Routes are deprecated. For new site-to-site setups, use [Networks Site-to-Site](/use-cases/remote-access/site-to-site) instead — it has per-Resource access control and is the actively developed system.
|
||||
|
||||
Routes remains the only option when you need site-to-site without any Policy gating traffic — the legacy "wide open" mode with empty Access Control Groups. Networks requires at least one Policy per Resource and has no equivalent.
|
||||
</Warning>
|
||||
@@ -22,7 +22,7 @@ Site A device ──► Routing Peer ──► NetBird Tunnel ──► Routing
|
||||
</div>
|
||||
|
||||
<Note>
|
||||
For the reverse — clientless devices at a site initiating connections to NetBird peers — see [Site-to-VPN](/manage/networks/use-cases/site-to-vpn).
|
||||
For the reverse — clientless devices at a site initiating connections to NetBird peers — see [Site-to-VPN](/use-cases/remote-access/site-to-vpn).
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -32,7 +32,7 @@ NetBird offers two ways to configure routing peers. Both are actively maintained
|
||||
**[Routes](/manage/network-routes) (legacy, deprecated)**
|
||||
- Distribution Groups and ACL Groups are configured separately.
|
||||
- ACL Groups are optional, which means a route without them grants unrestricted access to the destination CIDR for every peer in the Distribution Group.
|
||||
- Only needed today for [exit node](/manage/network-routes/use-cases/exit-nodes) setups. Use Networks for everything else, including [site-to-site](/manage/networks/use-cases/site-to-site).
|
||||
- Only needed today for [exit node](/use-cases/remote-access/exit-nodes) setups. Use Networks for everything else, including [site-to-site](/use-cases/remote-access/site-to-site).
|
||||
|
||||
## Mental model: how traffic flows
|
||||
|
||||
@@ -157,7 +157,7 @@ Every peer has two addresses — its **NetBird IP** (its `100.x` overlay address
|
||||
- a **peer-to-peer policy** (the input-chain accept), and
|
||||
- on userspace peers (Windows, macOS, Linux netstack), [`NB_ENABLE_LOCAL_FORWARDING`](#local-forwarding).
|
||||
|
||||
For the full setup — the file-server scenario, the commands, the Active Directory tie-in, and a fallback for when you can't set the flag — see [Reach Services on the Routing Peer](/manage/networks/use-cases/reach-services-on-the-routing-peer).
|
||||
For the full setup — the file-server scenario, the commands, the Active Directory tie-in, and a fallback for when you can't set the flag — see [Reach Services on the Routing Peer](/use-cases/remote-access/reach-services-on-the-routing-peer).
|
||||
|
||||
### Directionality is forced for routed traffic
|
||||
|
||||
@@ -258,7 +258,7 @@ When a peer is `Connected` but a resource behind it is still unreachable, [Troub
|
||||
description: 'When to enable or disable source IP rewriting on a route',
|
||||
},
|
||||
{
|
||||
href: '/manage/network-routes/use-cases/exit-nodes',
|
||||
href: '/use-cases/remote-access/exit-nodes',
|
||||
name: 'Exit Nodes',
|
||||
description: 'Route all internet-bound traffic through a controlled location',
|
||||
},
|
||||
|
||||
@@ -113,7 +113,7 @@ For the full kernel-level traffic walkthrough, host requirements (IP forwarding,
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
"To the peer" has a further subtlety: a peer-to-peer policy reaches the routing peer at its **NetBird IP** (its `100.x` overlay address). To reach it at its **LAN IP** — e.g. clients resolve its name to that address — you also need a resource that covers that IP (the route), and on userspace peers `NB_ENABLE_LOCAL_FORWARDING`. See [Reaching the routing peer itself](/manage/networks/how-routing-peers-work#reaching-the-routing-peer-itself) and the [Reach Services on the Routing Peer](/manage/networks/use-cases/reach-services-on-the-routing-peer) use case.
|
||||
"To the peer" has a further subtlety: a peer-to-peer policy reaches the routing peer at its **NetBird IP** (its `100.x` overlay address). To reach it at its **LAN IP** — e.g. clients resolve its name to that address — you also need a resource that covers that IP (the route), and on userspace peers `NB_ENABLE_LOCAL_FORWARDING`. See [Reaching the routing peer itself](/manage/networks/how-routing-peers-work#reaching-the-routing-peer-itself) and the [Reach Services on the Routing Peer](/use-cases/remote-access/reach-services-on-the-routing-peer) use case.
|
||||
</Note>
|
||||
|
||||
## Walkthrough: access two internal apps
|
||||
@@ -173,9 +173,9 @@ Before you depend on a Network in production, work through these:
|
||||
|
||||
## Networks or Network Routes?
|
||||
|
||||
Networks is the default for **every** remote-access scenario: VPN-to-Site, [Site-to-Site](/manage/networks/use-cases/site-to-site) (two clientless networks reaching each other through a routing peer at each end), and [Site-to-VPN](/manage/networks/use-cases/site-to-vpn) (a clientless device initiating connections to your overlay network).
|
||||
Networks is the default for **every** remote-access scenario: VPN-to-Site, [Site-to-Site](/use-cases/remote-access/site-to-site) (two clientless networks reaching each other through a routing peer at each end), and [Site-to-VPN](/use-cases/remote-access/site-to-vpn) (a clientless device initiating connections to your overlay network).
|
||||
|
||||
The only case that still requires [Routes](/manage/network-routes) is **[exit nodes](/manage/network-routes/use-cases/exit-nodes)**, which send a group's internet-bound traffic out through a chosen peer. For everything else, use Networks: it enforces access by default, while a Route without ACL Groups grants unrestricted access.
|
||||
The only case that still requires [Routes](/manage/network-routes) is **[exit nodes](/use-cases/remote-access/exit-nodes)**, which send a group's internet-bound traffic out through a chosen peer. For everything else, use Networks: it enforces access by default, while a Route without ACL Groups grants unrestricted access.
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -195,30 +195,35 @@ Networks keep resources private to your overlay network. If you instead need to
|
||||
description="Apply what you've learned to a real setup"
|
||||
items={[
|
||||
{
|
||||
href: '/manage/networks/use-cases/access-home-devices',
|
||||
href: '/use-cases/remote-access/access-home-devices',
|
||||
name: 'Access Home Devices',
|
||||
description: 'Reach a home NAS, media server, or IoT devices from anywhere.',
|
||||
},
|
||||
{
|
||||
href: '/manage/networks/use-cases/cloud-to-on-premise',
|
||||
href: '/use-cases/remote-access/cloud-to-on-premise',
|
||||
name: 'Cloud to On-Premise',
|
||||
description: 'Connect cloud workloads to databases and services on-prem.',
|
||||
},
|
||||
{
|
||||
href: '/manage/networks/use-cases/site-to-site',
|
||||
href: '/use-cases/remote-access/site-to-site',
|
||||
name: 'Site-to-Site',
|
||||
description: 'Connect two networks so clientless devices on each can talk.',
|
||||
},
|
||||
{
|
||||
href: '/manage/networks/use-cases/site-to-vpn',
|
||||
href: '/use-cases/remote-access/site-to-vpn',
|
||||
name: 'Site-to-VPN',
|
||||
description: 'Let clientless devices initiate connections to your overlay network.',
|
||||
},
|
||||
{
|
||||
href: '/manage/networks/use-cases/reach-services-on-the-routing-peer',
|
||||
href: '/use-cases/remote-access/reach-services-on-the-routing-peer',
|
||||
name: 'Reach Services on the Routing Peer',
|
||||
description: 'Reach a file server or SMB/DFS share when the file server itself runs the NetBird client.',
|
||||
},
|
||||
{
|
||||
href: '/use-cases/remote-access/active-directory',
|
||||
name: 'Active Directory & Windows File Shares',
|
||||
description: 'Reach domain controllers and SMB shares from remote peers.',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Access Home Devices (VPN-to-Site)
|
||||
|
||||
This guide shows how to access your home network devices from anywhere using the Networks feature.
|
||||
|
||||
<Note>
|
||||
For the mental model — see [How Routing Peers Work — Mental model](/manage/networks/how-routing-peers-work#mental-model-how-traffic-flows).
|
||||
</Note>
|
||||
|
||||
## What You'll Achieve
|
||||
|
||||
After following this guide, you'll be able to access your home NAS, media server, home automation, or any device on your home network from your laptop or phone—anywhere in the world.
|
||||
|
||||
```
|
||||
Your Laptop ──────► NetBird Tunnel ──────► Routing Peer ──────► Home NAS
|
||||
(peer) (at home) (no NetBird)
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A [NetBird cloud account](https://app.netbird.io/) or [self-hosted instance](/selfhosted/selfhosted-quickstart)
|
||||
- NetBird installed on your laptop or phone ([installation guide](/get-started/install))
|
||||
- An always-on device at home to serve as the routing peer (Raspberry Pi, NAS with Docker, old laptop, etc.)
|
||||
|
||||
## Step 1: Connect Your Laptop to NetBird
|
||||
|
||||
If you haven't already, install NetBird on your laptop and connect:
|
||||
|
||||
1. Download NetBird from [app.netbird.io/install](https://app.netbird.io/install)
|
||||
2. Run the application and click **Connect** in the system tray
|
||||
3. Complete the sign-up process in your browser
|
||||
4. Verify your device appears in the [NetBird dashboard](https://app.netbird.io/) under **Peers** → **User Devices**
|
||||
|
||||
## Step 2: Add Your Laptop to a User Group
|
||||
|
||||
1. In **Peers** → **User Devices**, select your laptop peer
|
||||
2. Under **Assigned Groups**, add a new group: "Home Users"
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-user-group.png" alt="Add user group" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 3: Find Your Home Subnet
|
||||
|
||||
Before configuring NetBird, identify your home network's subnet.
|
||||
|
||||
**On your routing peer device, run:**
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
ip route | grep -E "^[0-9]"
|
||||
|
||||
# macOS
|
||||
netstat -rn | grep default
|
||||
```
|
||||
|
||||
Look for your local subnet, typically something like `192.168.1.0/24` or `192.168.0.0/24`.
|
||||
|
||||
## Step 4: Create a Network for Your Home LAN
|
||||
|
||||
1. Go to **Network Routing** → **Networks** in the NetBird dashboard
|
||||
2. Click **Add Network**
|
||||
3. Name it "Home LAN" and click **Save**
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-network-home-lan.png" alt="Add network" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 5: Add Your Home Subnet as a Resource
|
||||
|
||||
1. In your new network, click **Add Resource**
|
||||
2. In the **Resource** tab, enter a name like "Home Subnet"
|
||||
3. Enter your home subnet (e.g., `192.168.1.0/24`)
|
||||
4. Expand **Additional Options** and under **Resource Groups**, create a group called `home-lan`
|
||||
5. Click **Continue** to proceed to the **Access Control** tab
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-resource-home-network.png" alt="Add resource" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
<Note>
|
||||
For more granular access, add specific device IPs instead of the entire subnet. For example, add `192.168.1.50/32` to only allow access to your NAS.
|
||||
</Note>
|
||||
|
||||
## Step 6: Create an Access Policy
|
||||
|
||||
1. In the **Access Control** tab, click **Add Policy**
|
||||
2. Set **Source** to "Home Users"
|
||||
3. Set **Destination** to `home-lan`
|
||||
4. Set **Protocol** to All
|
||||
5. Name it "Home LAN Access" and click **Add Policy**
|
||||
6. Click **Add Resource** to save the resource with its policy
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-policy-home-lan.png" alt="Add policy" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 7: Set Up the Routing Peer
|
||||
|
||||
The routing peer forwards traffic from NetBird to your local network. Use any always-on device:
|
||||
- Raspberry Pi
|
||||
- Synology NAS
|
||||
- Apple TV/Android TV
|
||||
- Home server
|
||||
|
||||
**Install NetBird on your routing peer:**
|
||||
|
||||
1. In the NetBird dashboard, go to **Settings** → **Setup Keys**
|
||||
2. Create a new setup key (one-time use recommended). Add `home-lan` to **Auto-assigned groups** and click **Create Setup Key**.
|
||||
|
||||
<Note>
|
||||
You can also add groups to peers manually after setup. Go to **Peers** → **Servers**, select the peer, and add groups under **Assigned Groups**.
|
||||
</Note>
|
||||
|
||||
3. On your routing peer, run:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
sudo netbird up --setup-key YOUR_SETUP_KEY
|
||||
```
|
||||
|
||||
4. In the Networks view, click **Add Routing Peer** on your Home LAN network
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-routing-peer.png" alt="Add routing peer button" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
5. Select your new peer and click **Add Routing Peer**
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/access-home-devices/add-routing-peer-home-network.png" alt="Add routing peer" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 8: Test the Connection
|
||||
|
||||
From your laptop (connected to a different network like mobile data or coffee shop WiFi):
|
||||
|
||||
```bash
|
||||
ping 192.168.1.1 # Your router
|
||||
ping 192.168.1.50 # Your NAS or other device
|
||||
```
|
||||
|
||||
You can now access your home devices from anywhere.
|
||||
|
||||
## Common Home Devices to Access
|
||||
|
||||
| Device | Typical Access Method |
|
||||
|--------|----------------------|
|
||||
| Synology/QNAP NAS | Web UI (port 5000/5001), SMB shares |
|
||||
| Home Assistant | Web UI (port 8123) |
|
||||
| Plex/Jellyfin | Web UI (port 32400/8096) |
|
||||
| Pi-hole | Web UI (port 80), DNS (port 53) |
|
||||
| Security cameras | RTSP streams, web interfaces |
|
||||
| Printers | IPP/AirPrint, web interfaces |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Can't reach home devices:**
|
||||
1. Verify the routing peer is online: check `netbird status` on the routing peer
|
||||
2. Ensure the routing peer can reach local devices: `ping 192.168.1.1` from the routing peer
|
||||
3. Check that your access policy includes your user/device
|
||||
|
||||
**Intermittent connectivity:**
|
||||
1. Ensure the routing peer has a stable internet connection
|
||||
2. Check if your ISP blocks VPN traffic (try a different port or protocol)
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **Need Site-to-Site?** If you want to connect two home networks together, see [Site-to-Site](/manage/networks/use-cases/site-to-site)
|
||||
- **Advanced configuration:** See [Masquerade](/manage/networks/masquerade) for masquerade options and persistent return-route configuration
|
||||
@@ -1,167 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Active Directory & Windows File Shares
|
||||
|
||||
Remote, domain-joined users expect their mapped drives, DFS (Distributed File System) paths, and domain login to *just work*, even when the domain controllers and file servers sit on a private LAN with nothing exposed publicly. This guide is the end-to-end journey for that over NetBird. It builds on two underlying pieces, [How Routing Peers Work](/manage/networks/how-routing-peers-work) and [Internal DNS Servers](/manage/dns/internal-dns-servers), and ties them together into a single setup.
|
||||
|
||||
<Note>
|
||||
**TL;DR** — AD over NetBird is [a handful of NetBird objects](#what-you-configure-in-net-bird): a routing peer, a route to the file server, a route to the domain controller, access control policies for both, and a DNS nameserver pointing at the DC.
|
||||
</Note>
|
||||
|
||||
The core idea: a domain-joined client's everyday actions quietly depend on **two kinds of server**, and both must be reachable over NetBird:
|
||||
|
||||
- the **domain controller (DC)**, for DNS, Kerberos authentication, and DFS namespace referrals;
|
||||
- the **file server(s)**, the machines that actually hold the shares.
|
||||
|
||||
```
|
||||
Remote user ──tunnel──► routing peer ──LAN──► Domain Controller (DNS, Kerberos, DFS referral)
|
||||
(NetBird) └─────► File server(s) (the SMB/DFS share data)
|
||||
```
|
||||
|
||||
## What one mapped drive actually depends on
|
||||
|
||||
When a user opens a DFS path such as `\\corp.example.com\dfs\share`, Windows:
|
||||
|
||||
1. resolves `corp.example.com` and finds a **domain controller** (ordinary DNS, plus special `SRV` records);
|
||||
2. asks the DC which file server actually holds that folder (the DFS **referral**);
|
||||
3. resolves that **file server's** name;
|
||||
4. connects to the file server over SMB, authenticated by **Kerberos** (tickets from the DC).
|
||||
|
||||
The domain controller is in almost every step: DNS (steps 1 and 3), the referral (step 2), and Kerberos (step 4). The file server itself only enters at step 4. If any one of these is unreachable — the DC, the file server, or the DNS linking them — the drive fails, often with an error that points nowhere near the real cause. The steps below make all of it reachable.
|
||||
|
||||
## Step 1: Decide where the NetBird client runs
|
||||
|
||||
You rarely install the NetBird client on every server. Pick one of two shapes:
|
||||
|
||||
- **A dedicated routing peer at the site.** A separate machine runs the NetBird client and routes to the DC and file servers across the LAN. Natural when shares are spread across several servers.
|
||||
- **The file server is the routing peer.** The NetBird client runs on the file server itself; the DC stays clientless behind it. Saves a machine, but on a Windows server it costs file-transfer performance (see the note below).
|
||||
|
||||
Use a dedicated routing peer, and make it a **Linux machine**: a small VM next to the servers is enough. The rest of this guide assumes that. If the file server itself runs the client, only Step 2 changes (reach it via [Reach Services on the Routing Peer](/manage/networks/use-cases/reach-services-on-the-routing-peer) instead), while Steps 3–5 (routing the DC, its ports, and DNS) apply either way.
|
||||
|
||||
<Note>
|
||||
**Why Linux: performance.** A Linux routing peer forwards traffic in the kernel at almost no cost; Windows and macOS peers process every packet in userspace, which caps file-transfer throughput well below LAN speed and loads the machine (see [How Routing Peers Work](/manage/networks/how-routing-peers-work)). Running the client directly on a Windows file server adds an extra internal delivery step on top. If remote users report documents opening much slower over NetBird than in the office, this choice is the first thing to check.
|
||||
</Note>
|
||||
|
||||
## Step 2: Make the file server(s) reachable
|
||||
|
||||
- **If a separate machine is the routing peer**, each file server is an ordinary host behind it. You will need:
|
||||
- a Network resource — a `/32`, or a domain resource set to its FQDN (e.g. `fileserver1.corp.example.com`)
|
||||
- an access control policy from your remote-users group to it on **TCP 445** (or whatever the service requires)
|
||||
- **If the file server is the routing peer**, clients address it at its own LAN IP (the *self-access* case) — follow [Reach Services on the Routing Peer](/manage/networks/use-cases/reach-services-on-the-routing-peer).
|
||||
|
||||
If your DFS folders are spread across several file servers, route each one. Find the targets from a machine with the DFS Management tools (RSAT) installed:
|
||||
|
||||
```powershell
|
||||
Get-DfsnFolderTarget '\\corp.example.com\dfs\share'
|
||||
```
|
||||
|
||||
Each result's `TargetPath` (for example `\\fileserver1.corp.example.com\share`) names a file server — add the server portion, `fileserver1.corp.example.com`, as a domain resource in your NetBird network.
|
||||
|
||||
## Step 3: Route the domain controller
|
||||
|
||||
The DC is almost always clientless and reached *through* the routing peer. Add it as a resource in the NetBird Network:
|
||||
|
||||
- a `/32` of the DC's IP, or
|
||||
- a domain resource for `corp.example.com`, whose A record points at the DCs (this routes them by name, and the routing peer must be able to resolve the domain).
|
||||
|
||||
Keep it granular — least privilege is the NetBird default, so route only what you need. A single `*.corp.example.com` wildcard covers the DC, file servers, and DFS targets in one resource, but trades away per-host control (see note).
|
||||
|
||||
<Note>
|
||||
A wildcard is one resource with **one policy scope** — the ports you open apply to *every* host under the domain, so you can't give the DC the full AD port set while limiting file servers to `445`. When you want that per-host scoping, use separate resources.
|
||||
</Note>
|
||||
|
||||
Routing the DC through a single routing peer works: domain logon, Kerberos, and DFS all function over it. One caution: don't make a single peer the *only* path to the DC if you can avoid it. It works, but for resilience add a second routing peer for high availability.
|
||||
|
||||
<Note>
|
||||
Running the NetBird client *on* a DC is a different pattern with its own caveats. See [Domain Controllers as Routing Peers](/manage/dns/internal-dns-servers#domain-controllers-as-routing-peers) and the [WireGuard port conflict](/manage/dns/internal-dns-servers#wire-guard-port-conflict-on-domain-controllers) note.
|
||||
</Note>
|
||||
|
||||
## Step 4: Allow the AD ports
|
||||
|
||||
Create a TCP policy and a UDP policy from your remote-users group to the DC, covering these baseline ports:
|
||||
|
||||
| Port | Protocol | Needed for |
|
||||
|---|---|---|
|
||||
| 53 | TCP/UDP | DNS — locating the DC and resolving AD `SRV` records |
|
||||
| 88 | TCP/UDP | Kerberos — domain logon |
|
||||
| 123 | UDP | Time sync (`w32time`) — clock skew beyond ~5 minutes breaks Kerberos, so this matters more than it looks |
|
||||
| 135 | TCP | RPC endpoint mapper — netlogon secure-channel setup |
|
||||
| 389 | TCP/UDP | LDAP / CLDAP — directory queries and DC location |
|
||||
| 445 | TCP | SMB — SYSVOL (Group Policy), file shares, and DFS |
|
||||
| 464 | TCP/UDP | Password changes and resets (kpasswd) — without it, a remote user whose password expires can't set a new one and is locked out |
|
||||
|
||||
NetBird renders one rule per access control policy, so a single policy can't mix protocols. Build **two** policies and sort each port into one or both:
|
||||
|
||||
- **TCP policy** — `53`, `88`, `135`, `389`, `445`, `464`
|
||||
- **UDP policy** — `53`, `88`, `123`, `389`, `464`
|
||||
|
||||
The ports that are both TCP and UDP (`53`, `88`, `389`, `464`) go in **both** policies.
|
||||
|
||||
### Beyond the basics: extra DC ports
|
||||
|
||||
The ports above cover the everyday AD experience: logon, Kerberos, DNS, time sync, password changes, SMB/DFS, and Group Policy. Some environments need more. Add these to the DC policies as your deployment requires (keeping one protocol per policy, so each new TCP port joins the TCP policy and each new UDP port the UDP policy):
|
||||
|
||||
| Port | Protocol | Needed for |
|
||||
|---|---|---|
|
||||
| 3268 / 3269 | TCP | **Global Catalog** (LDAP / LDAPS). In multi-domain forests, used by UPN-style logons (`user@domain`) and many directory-aware apps. |
|
||||
| 636 | TCP | **LDAPS**, for apps that bind to AD over TLS. |
|
||||
| 9389 | TCP | **AD Web Services**, the transport for the RSAT Active Directory PowerShell module (`Get-ADUser`, and similar). |
|
||||
| dynamic RPC | TCP | **Replication, some MMC consoles, and deep secure-channel checks.** Port 135 (the RPC endpoint mapper) is already in the baseline, but the high port range it hands out is not. Open it only if you manage AD this way. |
|
||||
|
||||
Each of these is independent — add only what you need; leaving one out affects only that feature.
|
||||
|
||||
## Step 5: Give clients corp DNS
|
||||
|
||||
A domain-joined client has to resolve many `corp.example.com` names: the file server, the DFS root, and the `SRV` records Windows uses to locate a DC. Add a **DNS nameserver** with `corp.example.com` as its **match domain**, pointing at the DC's IP address, and distribute it to your remote-users group. See [Internal DNS Servers](/manage/dns/internal-dns-servers).
|
||||
|
||||
<Note>
|
||||
A domain resource does not remove this need: the routing peer answers name-to-IP lookups but not the `SRV` / DC-locator records login and DFS require, so an AD client always needs this nameserver (and it only works once the DC is reachable, Step 3).
|
||||
</Note>
|
||||
|
||||
## Verify
|
||||
|
||||
Run these checks while signed in as the everyday domain user who will actually use the share. That user already holds a Kerberos login ticket from signing in, which is what makes the share connect cleanly.
|
||||
|
||||
**1. Check the file server answers on the file-sharing port.** File sharing (SMB) uses TCP port 445, so test that exact port:
|
||||
|
||||
```powershell
|
||||
Test-NetConnection <fileserver> -Port 445
|
||||
```
|
||||
|
||||
On Linux or macOS, use `nc -z <fileserver> 445` instead.
|
||||
|
||||
Do not use `ping` for this check. Because the policies above allow specific ports rather than all traffic, ICMP isn't included — so `ping` can fail even when file sharing works perfectly. A successful port 445 test is the reliable signal.
|
||||
|
||||
**2. Map a drive by name.** Run:
|
||||
|
||||
```
|
||||
net use G: \\corp.example.com\dfs\share
|
||||
```
|
||||
|
||||
It should connect exactly as it does in the office. Always use the server's **name** (the full `corp.example.com` address), never its IP. Windows logs you in by name using Kerberos — the ticket-based sign-in your domain controller provides. If you connect by IP (`\\<ip>\share`), Windows falls back to the older NTLM method, which usually fails here with *"the specified domain is not available."*
|
||||
|
||||
<Note>
|
||||
Two errors here look like a NetBird routing problem but are actually Windows quirks:
|
||||
|
||||
- Mapping a share **by IP address** can fail with **System error 1311**.
|
||||
- Connecting **with a typed-in username** (`net use ... /user:CORP\you`) can fail with **System error 1312**.
|
||||
|
||||
Both come from how Windows handles Kerberos logins, not from routing. Avoid them by testing the normal way: signed in as the domain user, connecting by name.
|
||||
</Note>
|
||||
|
||||
## What you configure in NetBird
|
||||
|
||||
The whole setup is these pieces — create each one and domain login, shares, and DFS all work:
|
||||
|
||||
- **A routing peer** — a peer at the site that routes to the DC and file servers: a dedicated Linux machine, or the file server itself. *(Step 1)*
|
||||
- **A route to the file server** — a Network resource (`/32` or FQDN, e.g. `fileserver1.corp.example.com`) for each share host. *(Step 2)*
|
||||
- **A route to the domain controller** — a Network resource (`/32` or `corp.example.com`). *(Step 3)*
|
||||
- **An access control policy to the file server** — on **TCP 445** (or whatever the service needs). *(Step 2)*
|
||||
- **Access control policies to the domain controller** — a TCP and a UDP policy on the AD ports. *(Step 4)*
|
||||
- **A DNS nameserver** — match domain `corp.example.com` pointing at the DC's IP, distributed to your remote-users group. *(Step 5)*
|
||||
|
||||
## Related
|
||||
|
||||
- [Reach Services on the Routing Peer](/manage/networks/use-cases/reach-services-on-the-routing-peer) — the self-access setup, for when the file server *is* the routing peer.
|
||||
- [How Routing Peers Work](/manage/networks/how-routing-peers-work) — forwarding, the two policy chains, and masquerade.
|
||||
- [Internal DNS Servers](/manage/dns/internal-dns-servers) — nameservers, Routing Peer DNS Resolution, and domain controllers.
|
||||
@@ -1,220 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Cloud to On-Premise Access (VPN-to-Site)
|
||||
|
||||
This guide shows how to connect cloud workloads to on-premise databases and services using the Networks feature.
|
||||
|
||||
<Note>
|
||||
For the mental model — see [How Routing Peers Work — Mental model](/manage/networks/how-routing-peers-work#mental-model-how-traffic-flows).
|
||||
</Note>
|
||||
|
||||
## What You'll Achieve
|
||||
|
||||
After following this guide, your cloud applications will be able to securely access on-premise databases, APIs, and services without exposing them to the public internet.
|
||||
|
||||
```
|
||||
Cloud VM ────► NetBird Tunnel ────► Routing Peer ────► Database Server
|
||||
(peer) (on-prem) (no NetBird)
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A [NetBird cloud account](https://app.netbird.io/) or [self-hosted instance](/selfhosted/selfhosted-quickstart)
|
||||
- Access to deploy VMs or containers in your cloud environment
|
||||
- Network configuration permissions in your cloud VPC
|
||||
|
||||
## Step 1: Find Your On-Premise Subnet
|
||||
|
||||
Before configuring NetBird, identify your data center network's subnet.
|
||||
|
||||
**On your routing peer device, run:**
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
ip route | grep -E "^[0-9]"
|
||||
```
|
||||
|
||||
Look for your local subnet, typically something like `10.100.0.0/24`.
|
||||
|
||||
## Step 2: Create a Network for On-Premise Resources
|
||||
|
||||
1. Go to **Network Routing** → **Networks** in the NetBird dashboard
|
||||
2. Click **Add Network**
|
||||
3. Name it "On-Premise Data Center" and click **Save**
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/cloud-to-on-premise/add-network-on-prem-datacenter.png" alt="Add network" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 3: Add Your Database as a Resource
|
||||
|
||||
1. In your new network, click **Add Resource**
|
||||
2. In the **Resource** tab, enter a name like "Database Servers"
|
||||
3. Enter your database subnet or specific IP (e.g., `10.100.0.0/24` or `10.100.0.50/32`)
|
||||
4. Expand **Additional Options** and under **Resource Groups**, create a group called `on-prem-databases`
|
||||
5. Click **Continue** to proceed to the **Access Control** tab
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/cloud-to-on-premise/add-resource-database-servers.png" alt="Add resource" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
<Note>
|
||||
For more granular access, add specific database IPs instead of the entire subnet. For example, add `10.100.0.50/32` to only allow access to your production database.
|
||||
</Note>
|
||||
|
||||
## Step 4: Create an Access Policy
|
||||
|
||||
1. In the **Access Control** tab, click **Add Policy**
|
||||
2. Set **Source** to "`cloud-workloads`" (you'll create this group in the next step)
|
||||
3. Set **Destination** to `on-prem-databases`
|
||||
4. Set **Protocol** to TCP
|
||||
5. Set **Ports** to the database ports (e.g., `5432` for PostgreSQL, `3306` for MySQL)
|
||||
6. Name it "Cloud to Database Access" and click **Add Policy**
|
||||
7. Click **Add Resource** to save the resource with its policy
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/cloud-to-on-premise/add-policy-on-prem-databases.png" alt="Add policy" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
## Step 5: Set Up the Routing Peer On-Premise
|
||||
|
||||
The routing peer forwards traffic from NetBird to your data center network. Install NetBird on a server that can reach the database:
|
||||
|
||||
1. In the NetBird dashboard, go to **Settings** → **Setup Keys**
|
||||
2. Create a new setup key (one-time use recommended). Add `on-prem-databases` to **Auto-assigned groups** and click **Create Setup Key**.
|
||||
|
||||
<p>
|
||||
<img src="/docs-static/img/manage/networks/use-cases/cloud-to-on-premise/create-new-setup-key-on-prem-db.png" alt="Create setup key" className="imagewrapper"/>
|
||||
</p>
|
||||
|
||||
<Note>
|
||||
You can also add groups to peers manually after setup. Go to **Peers** → **Servers**, select the peer, and add groups under **Assigned Groups**.
|
||||
</Note>
|
||||
|
||||
3. On your on-premise server, run:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
sudo netbird up --setup-key YOUR_SETUP_KEY
|
||||
```
|
||||
|
||||
4. In the Networks view, click **Add Routing Peer** on your On-Premise Data Center network
|
||||
5. Select your new peer and click **Add Routing Peer**
|
||||
|
||||
## Step 6: Deploy NetBird on `cloud-workloads`
|
||||
|
||||
Create a setup key for your cloud workloads:
|
||||
|
||||
1. In the NetBird dashboard, go to **Settings** → **Setup Keys**
|
||||
2. Create a new setup key. Add "`cloud-workloads`" to **Auto-assigned groups** and click **Create Setup Key**.
|
||||
|
||||
**For VMs:**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
sudo netbird up --setup-key YOUR_CLOUD_SETUP_KEY
|
||||
```
|
||||
|
||||
**For containers (Docker Compose):**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
netbird:
|
||||
image: netbirdio/netbird:latest
|
||||
network_mode: host
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
- NB_SETUP_KEY=YOUR_SETUP_KEY
|
||||
volumes:
|
||||
- netbird-config:/etc/netbird
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
netbird-config:
|
||||
```
|
||||
|
||||
**For Kubernetes:**
|
||||
|
||||
Use the [NetBird Kubernetes Operator](/manage/integrations/kubernetes) for production deployments.
|
||||
|
||||
## Step 7: Verify Cloud Workload Group Assignment
|
||||
|
||||
After deploying NetBird on your cloud workloads:
|
||||
|
||||
1. Go to **Peers** → **Servers** in the NetBird dashboard
|
||||
2. Verify your cloud workloads appear and are assigned to the "`cloud-workloads`" group
|
||||
3. If using a setup key with auto-assigned groups, this happens automatically
|
||||
|
||||
## Step 8: Configure Your Application
|
||||
|
||||
Update your application's database connection to use the on-premise IP:
|
||||
|
||||
```python
|
||||
# Example: Python with PostgreSQL
|
||||
conn = psycopg2.connect(
|
||||
host="10.100.0.50", # On-premise database IP
|
||||
dbname="production",
|
||||
user="app_user",
|
||||
password="secure_password"
|
||||
)
|
||||
```
|
||||
|
||||
Your cloud application can now securely access the on-premise database.
|
||||
|
||||
## Cloud-Specific Considerations
|
||||
|
||||
### AWS
|
||||
|
||||
- Use VPC endpoints where possible for AWS services
|
||||
- Security groups must allow traffic from the NetBird routing peer
|
||||
- Consider using an Auto Scaling group for the routing peer with a static ENI
|
||||
|
||||
### GCP
|
||||
|
||||
- Firewall rules must allow traffic from the routing peer's internal IP
|
||||
- Use instance groups for high availability
|
||||
- Enable IP forwarding on the routing peer instance
|
||||
|
||||
### Azure
|
||||
|
||||
- Network security groups must allow traffic from the routing peer
|
||||
- Consider using a Virtual Machine Scale Set for HA
|
||||
- Enable IP forwarding on the routing peer NIC
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Security
|
||||
|
||||
- Use dedicated setup keys per environment (e.g., `dev-workloads`, `staging-workloads`, `prod-workloads`)
|
||||
- Restrict access policies to specific ports and protocols
|
||||
- Enable [activity logging](/manage/activity) for compliance
|
||||
|
||||
### High Availability
|
||||
|
||||
- Deploy multiple routing peers and configure failover
|
||||
- Monitor routing peer health with your existing tools or set up [Notifications](/manage/settings/notifications) to get alerted when a routing peer disconnects
|
||||
- Use cloud-native load balancing where appropriate
|
||||
|
||||
### Performance
|
||||
|
||||
- Place routing peers close to the resources they serve
|
||||
- Use direct peering where possible (NetBird will automatically optimize paths)
|
||||
- Monitor latency and throughput between environments
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Cloud workload can't reach on-premise:**
|
||||
1. Verify the routing peer is online: `netbird status`
|
||||
2. Check the routing peer can reach the target: `ping 10.100.0.50`
|
||||
3. Verify access policies are configured correctly
|
||||
|
||||
**High latency:**
|
||||
1. Check routing peer placement and network connectivity
|
||||
2. Verify traffic is using direct peer-to-peer connections (not relays)
|
||||
3. Review cloud network configuration for bottlenecks
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **Need Multi-Cloud Site-to-Site?** If you need to connect cloud VPCs across providers, see [Site-to-Site](/manage/networks/use-cases/site-to-site)
|
||||
- **Advanced configuration:** See [Masquerade](/manage/networks/masquerade) for masquerade options and persistent return-route configuration
|
||||
@@ -1,52 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Reach Services on the Routing Peer
|
||||
|
||||
Most routing-peer guides cover reaching resources behind the peer. This one covers the opposite case: reaching a service that runs *on the routing peer itself*, at the peer's own LAN IP — the shape you get when the only machine running the NetBird client *is* the service host. The classic example is a file server that runs NetBird and serves SMB/DFS shares to remote users.
|
||||
|
||||
## The scenario
|
||||
|
||||
Every peer has two addresses: its **NetBird IP** (its `100.x` overlay address, the one in `netbird status`) and its **LAN IP** (its address on the local network). This case is about reaching a service at the peer's **LAN IP** — the address its name resolves to on the corporate network.
|
||||
|
||||
The NetBird client is installed only on the file server, so the file server *is* the routing peer. Remote users resolve the file server's name (and any DFS paths) to its LAN IP — but that address belongs to the routing peer itself, so traffic to it must be *delivered locally on the peer, not forwarded* to a network behind it. The symptom: DNS resolves, yet SMB connections and pings to the file server fail.
|
||||
|
||||
```
|
||||
Remote user ──tunnel──► File server = routing peer (its own SMB/DFS share at its LAN IP)
|
||||
(NetBird) └──► Domain Controller (clientless, on the same LAN)
|
||||
```
|
||||
|
||||
<Note>
|
||||
**Performance.** On a Linux service host this shape serves at full speed — a Linux file server or NAS can happily be its own routing peer. On Windows and macOS the client's data path runs in userspace, which limits file-transfer throughput; for busy shares on a Windows server, a dedicated Linux routing peer in front is the faster shape (see [Step 1 of the Active Directory guide](/manage/networks/use-cases/active-directory#step-1-decide-where-the-net-bird-client-runs)).
|
||||
</Note>
|
||||
|
||||
## The setup
|
||||
|
||||
The target *is* the routing peer, addressed by its own LAN IP. Set up the following together:
|
||||
|
||||
1. **A route to the address** — a resource covering the file server's LAN IP: a `/32`, or a domain resource set to its DNS name (the peer resolves its own name and keeps the route current if the IP changes).
|
||||
2. **A peer-to-peer policy** from your users' group to the routing peer (or routing peer group), on the service port (SMB = **TCP 445**). Reaching the peer *itself* is a separate permission from reaching machines *behind* it — this grants it.
|
||||
3. **On a Windows or macOS routing peer, set the `NB_ENABLE_LOCAL_FORWARDING` [environment variable](/client/environment-variables)** — it lets the NetBird client deliver to a service on its own LAN IP, not just forward onward:
|
||||
|
||||
```powershell
|
||||
netbird service reconfigure --service-env NB_ENABLE_LOCAL_FORWARDING=true
|
||||
```
|
||||
|
||||
A Linux peer doesn't need this with its default kernel forwarding — only in netstack mode.
|
||||
|
||||
Steps 1 and 3 exist only because clients reach the file server at its **LAN IP**. Reaching a peer at its **NetBird IP** needs only the policy in step 2 — every client already has a route to it, with no resource to add and no forwarding flag.
|
||||
|
||||
With these in place, a mapped drive to the share works unchanged — reached at its LAN IP over the tunnel.
|
||||
|
||||
**Domain-joined clients (AD/DFS)** need one more thing — a NetBird **DNS nameserver** for your AD domain. Add one with the match domain `corp.example.com` pointing at the DC's IP address (e.g. `10.0.0.10`), so clients resolve corp DNS and can log in. The DC must also be reachable over NetBird. See **[Active Directory & Windows File Shares](/manage/networks/use-cases/active-directory)** for the full setup.
|
||||
|
||||
## Verify
|
||||
|
||||
- Test reachability with `Test-NetConnection <host> -Port <port>` (or `nc -z`), not `ping`. ICMP needs its own peer-to-peer policy; a service working while `ping` fails is the signature of a missing ICMP policy, not a broken route.
|
||||
- The service should now answer at the routing peer's LAN IP over the tunnel — for a file server, a mapped drive opens unchanged.
|
||||
- Still unreachable? [Troubleshooting resource connectivity](/help/troubleshooting-resource-connectivity) isolates whether the problem is DNS, the route, the policy, forwarding on the peer, or the service itself.
|
||||
|
||||
## Fallback: resolve the name to the NetBird IP
|
||||
|
||||
If you can't set `NB_ENABLE_LOCAL_FORWARDING` on the file server, there's an alternative that needs no resource, route, or forwarding flag: make each client resolve the file server's name to its NetBird IP (its `100.x` address) instead of its LAN IP — with a `hosts` file entry or a Windows NRPT rule (a per-name DNS override). The client then connects to it directly over the NetBird overlay. Logins still work, because Kerberos is tied to the server's *name*, not its IP address.
|
||||
|
||||
Treat this as a *last resort, not the main path*: it has to be set up on every client, whereas the setup above is configured once in NetBird and is invisible to clients.
|
||||
@@ -1,189 +0,0 @@
|
||||
import { Note } from '@/components/mdx'
|
||||
|
||||
# Site-to-Site
|
||||
|
||||
Site-to-Site connects two networks through routing peers at each end. Neither end-device needs NetBird installed — the routing peers forward traffic across the NetBird tunnel. This guide builds it with [Networks](/manage/networks), where each site is a Resource gated by its own Policy.
|
||||
|
||||
## Architecture
|
||||
|
||||
<div className="not-prose w-fit max-w-full">
|
||||
|
||||
```
|
||||
Site A device ──► Routing Peer ──► NetBird Tunnel ──► Routing Peer ──► Site B device
|
||||
(no NetBird) (peer) (peer) (no NetBird)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<Note>
|
||||
Networks is the recommended way to build site-to-site. It has per-Resource access control, is Zero Trust by default, and is the actively developed system.
|
||||
|
||||
For the reverse — clientless devices at a site initiating connections to NetBird peers — see [Site-to-VPN](/manage/networks/use-cases/site-to-vpn).
|
||||
</Note>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An always-on device at each site to act as the routing peer
|
||||
- Different subnets at each site. If both sites use the same range (e.g. `192.168.1.0/24`), see [Overlapping Routes](/manage/network-routes/overlapping-routes)
|
||||
|
||||
## Example
|
||||
|
||||
Two sites, A and B:
|
||||
- Site A: `10.0.0.0/24`, routing peer group `site-a-routers`
|
||||
- Site B: `10.1.0.0/24`, routing peer group `site-b-routers`
|
||||
|
||||
## Step 1: Create setup keys for each site
|
||||
|
||||
Create one setup key per site with an auto-assigned group for that site's routing peers.
|
||||
|
||||
1. Go to **Settings** → **Setup Keys** → **Create Setup Key**
|
||||
2. For Site A: name "Site A Routing Peer", auto-assign group `site-a-routers`
|
||||
3. Repeat for Site B with group `site-b-routers`
|
||||
|
||||
<Note>
|
||||
You can also assign groups manually after the peer connects, under **Peers** → **Servers** → select peer → **Assigned Groups**.
|
||||
</Note>
|
||||
|
||||
## Step 2: Install NetBird on the routing peers
|
||||
|
||||
On each site's routing peer:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
sudo netbird up --setup-key YOUR_SETUP_KEY
|
||||
```
|
||||
|
||||
## Step 3: Create a Network for each site
|
||||
|
||||
Each site becomes its own Network: a Resource for that site's subnet, served by that site's routing peers.
|
||||
|
||||
**Network A:**
|
||||
|
||||
1. Go to **Network Routing** → **Networks** → **Add Network**, name it `site-a`, and click **Create Network**
|
||||
2. Inside the network, click **Add Resource**:
|
||||
- Enter a name like `site-a-subnet`
|
||||
- Enter the address `10.0.0.0/24` (a subnet, or a single host like `10.0.0.50/32`)
|
||||
- Expand **Additional Options** and under **Resource Groups**, create a group called `site-a-cidr` (this group represents the subnet for use in policies)
|
||||
3. Click **Add Routing Peer**, select the `site-a-routers` group, and leave **Masquerade** enabled (the default)
|
||||
|
||||
<Note>
|
||||
Leave Masquerade enabled on both routing peers. NetBird's tunnel drops traffic whose source isn't the peer's NetBird IP, so Masquerade is what makes site-to-site work — disabling it on a routing peer breaks the flow. Masquerade is enabled by default everywhere, and the toggle to turn it off only exists on Linux.
|
||||
|
||||
NetBird only performs the required outbound SNAT itself on Linux routing peers. Other platforms (OPNsense and pfSense are common examples) don't do this SNAT unless you configure it manually, so use a Linux routing peer for site-to-site.
|
||||
</Note>
|
||||
|
||||
**Network B:** repeat the steps — name `site-b`, Resource address `10.1.0.0/24` with group `site-b-cidr`, and routing peer group `site-b-routers`.
|
||||
|
||||
## Step 4: Create access control policies
|
||||
|
||||
Networks requires a Policy on every Resource — without one, the dashboard will not allow access to it. Add one Policy per Network:
|
||||
|
||||
- **Network A's Resource:** Source Groups = `site-b-routers` → destination = the `site-a-subnet` Resource
|
||||
- **Network B's Resource:** Source Groups = `site-a-routers` → destination = the `site-b-subnet` Resource
|
||||
|
||||
Tighten by protocol/port if needed; use **All** to allow any.
|
||||
|
||||
## Step 5: Tell clientless devices about the remote subnet
|
||||
|
||||
Devices without NetBird need a static route pointing to the local routing peer.
|
||||
|
||||
**Router-level (recommended)** — add a static route on the site's router so all devices inherit it:
|
||||
|
||||
```
|
||||
Destination: 10.1.0.0/24 # remote network
|
||||
Gateway: 10.0.0.50 # local routing peer
|
||||
```
|
||||
|
||||
**Per-device fallback** — if you can't touch the router, add the route on each device instead.
|
||||
|
||||
**Windows** (PowerShell as Administrator) — `-p` makes it persistent:
|
||||
|
||||
```powershell
|
||||
route -p add 10.1.0.0 mask 255.255.255.0 10.0.0.50
|
||||
```
|
||||
|
||||
**Linux** — first test the route (this form disappears on the next reboot):
|
||||
|
||||
```bash
|
||||
sudo ip route add 10.1.0.0/24 via 10.0.0.50
|
||||
```
|
||||
|
||||
Once a peer at the other site is reachable, make it permanent. The method depends on which network manager the device uses — check with:
|
||||
|
||||
```bash
|
||||
ls /etc/netplan/
|
||||
```
|
||||
|
||||
Follow **only one** of the two methods below — the one that matches what `ls` showed. They're alternatives, not consecutive steps: if you see `.yaml` files use Netplan (most Ubuntu hosts); if the directory is empty or missing use systemd-networkd (Debian, minimal installs). Don't mix them — on Netplan hosts, systemd-networkd config you add by hand is silently ignored.
|
||||
|
||||
Both methods need your LAN interface name — find it with `ip -br addr` (look for the connection carrying the device's local IP, e.g. `eth0` or `ens18`). Substitute it wherever the steps below show `<IFACE>`.
|
||||
|
||||
**Option A — Netplan** (you saw `.yaml` files) — open the file `ls` showed (e.g. `50-cloud-init.yaml`) in a text editor. `nano` is the simplest; this command opens the file in it (run `sudo apt install nano` first if it's missing):
|
||||
|
||||
```bash
|
||||
sudo nano /etc/netplan/50-cloud-init.yaml
|
||||
```
|
||||
|
||||
Find your interface under `ethernets:` and add the route. If a `routes:` list is already there, add the `- to:` lines to it — don't create a second `routes:` key:
|
||||
|
||||
```yaml
|
||||
network:
|
||||
version: 2
|
||||
ethernets:
|
||||
<IFACE>: # your interface, from ip -br addr
|
||||
dhcp4: true # whatever was already here
|
||||
routes: # add this block (or reuse an existing routes: list)
|
||||
- to: 10.1.0.0/24 # remote network
|
||||
via: 10.0.0.50 # local routing peer
|
||||
```
|
||||
|
||||
Save and exit. In nano: press `Ctrl+O` then `Enter` to write the file, then `Ctrl+X` to quit. Then apply the change:
|
||||
|
||||
```bash
|
||||
sudo netplan apply
|
||||
```
|
||||
|
||||
<Note>
|
||||
Recent Netplan needs `0600` permissions on files under `/etc/netplan/`. Run `sudo chmod 0600 /etc/netplan/*.yaml` if `netplan apply` warns.
|
||||
</Note>
|
||||
|
||||
**Option B — systemd-networkd** (the `/etc/netplan/` directory was empty) — create a drop-in for your interface. Replace both `<IFACE>` below with your interface name, then paste the block — it creates the file and reloads in one go:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/systemd/network/<IFACE>.network.d
|
||||
sudo tee /etc/systemd/network/<IFACE>.network.d/100-netbird.conf > /dev/null <<'EOF'
|
||||
[Route]
|
||||
Destination=10.1.0.0/24
|
||||
Gateway=10.0.0.50
|
||||
EOF
|
||||
sudo networkctl reload
|
||||
```
|
||||
|
||||
Repeat this on the other site with the values swapped, so Site B's router or devices know to reach `10.0.0.0/24` via the local Site B routing peer. Bidirectional site-to-site needs the static routes on both sides.
|
||||
|
||||
This step assumes Masquerade is enabled on both routing peers (the default in Step 3). Site-to-site over Networks requires Masquerade to be on — disabling it on a routing peer causes the WireGuard tunnel to drop traffic whose source isn't the peer's NetBird IP, so source-IP preservation isn't currently supported for site-to-site. If you need to preserve source IPs end to end, use the [Routes site-to-site setup](/manage/network-routes/use-cases/site-to-site) instead, which supports running with Masquerade disabled.
|
||||
|
||||
## Step 6: Verify
|
||||
|
||||
From Site A, ping a device at Site B:
|
||||
|
||||
```bash
|
||||
ping 10.1.0.100
|
||||
```
|
||||
|
||||
Reverse from Site B to confirm both directions work. The destination sees the connection coming from its local routing peer's LAN IP — source IPs are masqueraded at both routing peers.
|
||||
|
||||
## Cloud routing peers
|
||||
|
||||
When the routing peer is a cloud instance, the VPC needs to allow it to forward traffic on behalf of other addresses:
|
||||
|
||||
- **AWS**: Disable the source/destination check on the routing peer's ENI. Add a VPC route table entry with the remote CIDR as the destination and the routing peer's ENI as the target. Security groups must allow traffic from the routing peer.
|
||||
- **GCP**: Enable IP forwarding on the instance. Add a custom route in the VPC with the remote CIDR as the destination and the routing peer instance as the next hop. Firewall rules must allow traffic from the routing peer's internal IP.
|
||||
- **Azure**: Enable IP forwarding on the routing peer's NIC. Add a route table entry with the remote CIDR pointing at the routing peer. Network security groups must allow the traffic.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Masquerade](/manage/networks/masquerade) — how source NAT works on routing peers
|
||||
- [Site-to-VPN](/manage/networks/use-cases/site-to-vpn) — clientless devices initiating connections to NetBird peers
|
||||
- [Access Home Devices](/manage/networks/use-cases/access-home-devices) — reach a single site from your NetBird peers
|
||||
- [Routes Site-to-Site](/manage/network-routes/use-cases/site-to-site) — legacy approach for scenarios that require source-IP preservation or Routes-specific behavior
|
||||
@@ -1,407 +0,0 @@
|
||||
import { Note, Warning } from '@/components/mdx'
|
||||
|
||||
# Site-to-VPN: Clientless Devices Reaching NetBird Peers
|
||||
|
||||
This guide shows how to let a device that does **not** have NetBird installed
|
||||
initiate a connection to a NetBird peer over the overlay — the reverse of the
|
||||
more common VPN-to-Site direction.
|
||||
|
||||
## What You'll Achieve
|
||||
|
||||
After following this guide, a clientless device on your local network can
|
||||
reach a NetBird peer by its overlay IP or NetBird DNS name. Typical examples:
|
||||
|
||||
- An on-premise monitoring system pushing metrics to a NetBird-connected
|
||||
collector
|
||||
- A legacy server initiating outbound backups to a NetBird peer in the cloud
|
||||
- An office printer reporting status to a NetBird-connected management
|
||||
application
|
||||
|
||||
```
|
||||
Clientless Device ──► Routing Peer ──► NetBird Overlay ──► NetBird Peer
|
||||
(no NetBird) (peer) (peer)
|
||||
```
|
||||
|
||||
<Warning>
|
||||
The routing peer must perform **outbound source NAT** for site traffic
|
||||
entering the NetBird overlay. The dashboard **Masquerade** flag does not
|
||||
cover this direction on any route — you must install the SNAT rule
|
||||
manually on the routing peer (or on its upstream firewall) on every
|
||||
platform. Without this, the overlay peer drops the traffic at its access
|
||||
control.
|
||||
</Warning>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A device on the local network to serve as the routing peer. Linux is
|
||||
assumed throughout this guide; on other platforms the steps are the
|
||||
same but the [Step 3](#step-3-configure-the-outbound-snat) SNAT rule
|
||||
has to be installed via the platform's native NAT mechanism.
|
||||
- A separate device running the NetBird client that the clientless device
|
||||
needs to reach
|
||||
- The ability to either add a static route on the clientless device (or its
|
||||
upstream router), or to install a port-forwarding rule on the routing peer
|
||||
— both options are covered below
|
||||
|
||||
## Example Setup
|
||||
|
||||
- **Local site:** `192.168.50.0/24`
|
||||
- **Routing peer (`site-router`):** site IP `192.168.50.10`, NetBird IP
|
||||
assigned at enrollment
|
||||
- **Clientless device:** `192.168.50.20`
|
||||
- **Target NetBird peer (`overlay-peer`):** runs the NetBird client; we
|
||||
reach it on TCP port `8080`
|
||||
|
||||
## Step 1: Create Setup Keys with Groups
|
||||
|
||||
Before installing NetBird on the routing peer, create a setup key with an
|
||||
auto-assigned group so the peer lands in the right place:
|
||||
|
||||
1. Go to **Settings** → **Setup Keys** in the NetBird dashboard
|
||||
2. Click **Create Setup Key**
|
||||
3. Configure:
|
||||
- Name: "Site Routing Peer"
|
||||
- Auto-assigned groups: create and add `site-routing-peers`
|
||||
4. Click **Create** and note the key
|
||||
|
||||
The target peer is a regular NetBird peer; nothing special needs to be
|
||||
configured on it for this scenario. If the target peer is a service or
|
||||
appliance (not a user device), create a second setup key for it the same
|
||||
way and add it to a group like `overlay-peers`. User peers — laptops
|
||||
and workstations — enroll through SSO instead and pick up their group via
|
||||
your existing group assignments.
|
||||
|
||||
## Step 2: Deploy the Routing Peer
|
||||
|
||||
Install NetBird on the routing peer and enroll it:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkgs.netbird.io/install.sh | sh
|
||||
sudo netbird up --setup-key YOUR_SITE_SETUP_KEY
|
||||
```
|
||||
|
||||
Confirm the peer appears in the dashboard and shows the `site-routing-peers`
|
||||
group.
|
||||
|
||||
## Step 3: Configure the Outbound SNAT
|
||||
|
||||
The routing peer must SNAT site traffic onto its NetBird interface so the
|
||||
overlay peer's access control sees a NetBird IP it recognises — the
|
||||
overlay peer's per-policy ipset only contains the NetBird IPs of source
|
||||
peers, so unrewritten packets sourced from a routed CIDR are dropped.
|
||||
|
||||
This step is **required on every routing peer**, regardless of OS or
|
||||
WireGuard mode. The dashboard **Masquerade** flag (Step 4) does not
|
||||
install a SNAT for the Site-to-VPN direction.
|
||||
|
||||
### Linux
|
||||
|
||||
Install the SNAT rule via `iptables-persistent` so it survives reboot.
|
||||
This works on systems using either `iptables-legacy` or `iptables-nft`
|
||||
underneath:
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y iptables-persistent
|
||||
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o wt0 -j MASQUERADE
|
||||
sudo netfilter-persistent save
|
||||
```
|
||||
|
||||
### Other platforms
|
||||
|
||||
On non-Linux routing peers, install the equivalent rule via the
|
||||
platform's native NAT mechanism. Any outbound source NAT that rewrites
|
||||
the site-CIDR source to the routing peer's NetBird IP (or to the `wt0`
|
||||
interface address) on egress from `wt0` is sufficient.
|
||||
|
||||
## Step 4: Create the Network
|
||||
|
||||
In the NetBird dashboard:
|
||||
|
||||
1. Go to **Network Routing** → **Networks** and click **Add Network**
|
||||
2. Name: `site-50-network`
|
||||
3. Click **Create Network**
|
||||
|
||||
Now add the site CIDR as a resource:
|
||||
|
||||
1. In the new network, click **Add Resource**
|
||||
2. Configure:
|
||||
- **Name:** `site-50`
|
||||
- **Address:** `192.168.50.0/24`
|
||||
- **Type:** Subnet
|
||||
- **Groups:** create and add `site-50-cidr` (this group represents the
|
||||
site CIDR for use in policies)
|
||||
3. Click **Add Resource**
|
||||
|
||||
Attach the routing peer:
|
||||
|
||||
1. In the network, click **Add Routing Peer**
|
||||
2. Select `site-router` (or the `site-routing-peers` group)
|
||||
3. **Masquerade:** Leave at the default. This flag controls SNAT for
|
||||
traffic flowing **outbound from NetBird peers through the routing
|
||||
peer** (the VPN-to-Site direction). It has no effect on Site-to-VPN
|
||||
traffic, which is what this guide configures — the manual SNAT from
|
||||
[Step 3](#step-3-configure-the-outbound-snat) is what makes Site-to-VPN
|
||||
work.
|
||||
4. Click **Save**
|
||||
|
||||
## Step 5: Create the Access Policy
|
||||
|
||||
The routing peer needs to be allowed to reach the target peer over the
|
||||
overlay. Because Step 3's SNAT rewrites the source to the routing peer's
|
||||
NetBird IP, the policy uses peer groups:
|
||||
|
||||
1. Go to **Access Control** → **Policies** and click **Add Policy**
|
||||
2. Configure:
|
||||
- **Name:** `Site Router to Overlay Peer`
|
||||
- **Protocol:** `TCP`
|
||||
- **Ports:** `8080` (or `All` to allow any port)
|
||||
- **Source Groups:** `site-routing-peers`
|
||||
- **Destination Groups:** `overlay-peers`
|
||||
3. Click **Add Policy**
|
||||
|
||||
## Step 6: Direct Site Traffic Through the Routing Peer
|
||||
|
||||
Tell the clientless device — or the site's upstream router — to send
|
||||
traffic destined for your account's NetBird IP range through the routing
|
||||
peer.
|
||||
|
||||
### Find your account's NetBird range
|
||||
|
||||
NetBird assigns each account a single `/16` block from inside the
|
||||
`100.64.0.0/10` CGNAT range (one of 64 possible blocks such as
|
||||
`100.64.0.0/16`, `100.121.0.0/16`, `100.127.0.0/16`, …). The block is
|
||||
chosen randomly per account and can be customised. Use that `/16` for the
|
||||
site's static route — not the whole `/10` — so you don't route unrelated
|
||||
CGNAT addresses through the routing peer.
|
||||
|
||||
Read it off any enrolled peer:
|
||||
|
||||
```bash
|
||||
$ netbird status | grep "NetBird IP"
|
||||
NetBird IP: 100.121.195.4/16
|
||||
# → this account's block is 100.121.0.0/16
|
||||
```
|
||||
|
||||
In the examples below, replace `100.121.0.0/16` with your own block.
|
||||
|
||||
### Install the route
|
||||
|
||||
**On a Linux clientless device with netplan** (Ubuntu Server default):
|
||||
|
||||
```yaml
|
||||
# /etc/netplan/99-netbird-route.yaml
|
||||
network:
|
||||
version: 2
|
||||
ethernets:
|
||||
eth0: # the interface holding the device's site IP
|
||||
routes:
|
||||
- to: 100.121.0.0/16
|
||||
via: 192.168.50.10
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo chmod 600 /etc/netplan/99-netbird-route.yaml
|
||||
sudo netplan apply
|
||||
```
|
||||
|
||||
**On a Linux clientless device with NetworkManager** (RHEL / Fedora /
|
||||
desktop distros):
|
||||
|
||||
```bash
|
||||
sudo nmcli connection modify "<connection>" \
|
||||
+ipv4.routes "100.121.0.0/16 192.168.50.10"
|
||||
sudo nmcli connection up "<connection>"
|
||||
```
|
||||
|
||||
**On Windows** (the `-p` flag persists the route across reboots):
|
||||
|
||||
```powershell
|
||||
route -p add 100.121.0.0 mask 255.255.0.0 192.168.50.10
|
||||
```
|
||||
|
||||
**On a site router that issues DHCP:** add a classless static route option
|
||||
(DHCP option 121) pointing your account's `/16` to the routing peer. Every
|
||||
device on the network will then learn the route automatically.
|
||||
|
||||
The clientless device can now reach the target peer by its NetBird IP:
|
||||
|
||||
```bash
|
||||
curl http://<TARGET_PEER_NETBIRD_IP>:8080/
|
||||
```
|
||||
|
||||
To use NetBird's DNS names instead of IPs, see
|
||||
[Resolving NetBird DNS Names](#resolving-netbird-dns-names) below.
|
||||
|
||||
If you cannot add a static route on the clientless device or the site
|
||||
router — or you only need to expose a small number of specific services —
|
||||
see [Appendix: Per-Service Port Forwarding](#appendix-per-service-port-forwarding)
|
||||
for a DNAT-based alternative.
|
||||
|
||||
## Test Connectivity
|
||||
|
||||
From the clientless device:
|
||||
|
||||
```bash
|
||||
curl -v http://<TARGET_PEER_NETBIRD_IP>:8080/
|
||||
```
|
||||
|
||||
Verify on the target peer that the request arrived:
|
||||
|
||||
```bash
|
||||
sudo ss -tan | grep :8080
|
||||
```
|
||||
|
||||
The connection appears as a `TIME-WAIT` entry for about a minute after
|
||||
curl closes; its remote address is the **routing peer's NetBird IP**,
|
||||
not the clientless device's local IP.
|
||||
|
||||
## Resolving NetBird DNS Names
|
||||
|
||||
By default, the clientless device has no way to resolve `*.netbird.cloud`
|
||||
hostnames — that lookup happens locally on each NetBird peer. You can
|
||||
publish those names to the site by running a forwarding resolver on the
|
||||
routing peer.
|
||||
|
||||
A minimal `dnsmasq` configuration on the routing peer:
|
||||
|
||||
```ini
|
||||
# /etc/dnsmasq.d/netbird.conf
|
||||
bind-interfaces
|
||||
listen-address=192.168.50.10
|
||||
interface=eth0
|
||||
|
||||
# Forward NetBird-managed names to this peer's local NetBird resolver.
|
||||
# The NetBird daemon listens on the peer's NetBird IP, port 53.
|
||||
server=/netbird.cloud/<ROUTING_PEER_NETBIRD_IP>
|
||||
|
||||
# Everything else to upstream
|
||||
server=8.8.8.8
|
||||
server=1.1.1.1
|
||||
```
|
||||
|
||||
Then point the clientless device's DNS at `192.168.50.10` (via DHCP,
|
||||
`/etc/resolv.conf`, or static configuration) and use the NetBird hostname
|
||||
directly:
|
||||
|
||||
```bash
|
||||
curl http://overlay-peer.netbird.cloud:8080/
|
||||
```
|
||||
|
||||
<Note>
|
||||
The NetBird daemon binds its DNS resolver on the peer's own NetBird IP,
|
||||
not on `127.0.0.1`. Substitute the routing peer's actual NetBird IP into
|
||||
the `server=/netbird.cloud/...` line — you can find it with
|
||||
`netbird status` on the routing peer.
|
||||
</Note>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Connection times out from the clientless device.**
|
||||
|
||||
Check that the static route is in place:
|
||||
|
||||
```bash
|
||||
ip route get <TARGET_PEER_NETBIRD_IP>
|
||||
# Should show "via 192.168.50.10 dev <iface>"
|
||||
```
|
||||
|
||||
If you are using the appendix DNAT alternative instead, verify the
|
||||
forwarding rule on the routing peer:
|
||||
|
||||
```bash
|
||||
sudo iptables -t nat -L PREROUTING -n -v
|
||||
# Should show your DNAT rule with non-zero packet counters when traffic flows
|
||||
```
|
||||
|
||||
**Routing peer receives packets but they don't reach the target peer.**
|
||||
|
||||
Check that IP forwarding is enabled and confirm the target peer is reachable
|
||||
from the routing peer directly:
|
||||
|
||||
```bash
|
||||
# On the routing peer
|
||||
cat /proc/sys/net/ipv4/ip_forward # should be 1
|
||||
curl http://<TARGET_PEER_NETBIRD_IP>:8080/ # should succeed
|
||||
```
|
||||
|
||||
If the second command fails, the access policy is wrong — verify the policy
|
||||
allows `site-routing-peers` → target peer's group on the required port.
|
||||
|
||||
**Target peer receives packets but drops them.**
|
||||
|
||||
The outbound SNAT from
|
||||
[Step 3](#step-3-configure-the-outbound-snat) is missing or not effective.
|
||||
On the routing peer, packets going out `wt0` must have their source IP
|
||||
rewritten to the routing peer's NetBird IP:
|
||||
|
||||
```bash
|
||||
# Verify packet counters on the MASQUERADE rule installed in Step 3:
|
||||
sudo iptables -t nat -L POSTROUTING -n -v
|
||||
# Or watch overlay traffic on the way out:
|
||||
sudo tcpdump -ni wt0 'src net 192.168.50.0/24'
|
||||
# Seeing site IPs here means SNAT is NOT firing; the target peer will drop.
|
||||
```
|
||||
|
||||
If the Step 3 rule is missing or its counters stay at zero, re-install it
|
||||
(and add it to your persistence layer so it survives a reboot):
|
||||
|
||||
```bash
|
||||
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o wt0 -j MASQUERADE
|
||||
```
|
||||
|
||||
**DNS resolution returns NXDOMAIN or times out.**
|
||||
|
||||
Confirm the `server=/netbird.cloud/...` line in
|
||||
`/etc/dnsmasq.d/netbird.conf` still matches the routing peer's current
|
||||
NetBird IP — re-enrolling the peer changes it. Isolate from the
|
||||
clientless device:
|
||||
|
||||
```bash
|
||||
dig @<ROUTING_PEER_SITE_IP> <hostname>.netbird.cloud
|
||||
```
|
||||
|
||||
A timeout means `dnsmasq` isn't reachable on the routing peer's site IP
|
||||
(check `listen-address` in the config). `SERVFAIL` means `dnsmasq`
|
||||
received the query but its forward to the NetBird resolver failed.
|
||||
`NXDOMAIN` means the NetBird resolver answered but doesn't know that
|
||||
hostname — verify the target peer's actual FQDN with `netbird status`
|
||||
on the peer itself.
|
||||
|
||||
## Appendix: Per-Service Port Forwarding
|
||||
|
||||
If you cannot change routing on the site — for example, the clientless
|
||||
device's IP stack is fixed and the upstream router is out of your control —
|
||||
you can still expose individual NetBird services through the routing peer
|
||||
using DNAT. This avoids the [Step 6](#step-6-direct-site-traffic-through-the-routing-peer)
|
||||
static route entirely, but each service has to be configured explicitly.
|
||||
|
||||
First identify the routing peer's site-facing interface:
|
||||
|
||||
```bash
|
||||
ip -br addr
|
||||
# Pick the interface that holds the routing peer's site IP (e.g. eth0, ens18).
|
||||
```
|
||||
|
||||
Then install the DNAT rule on the routing peer:
|
||||
|
||||
```bash
|
||||
sudo iptables -t nat -A PREROUTING -i <site-iface> -p tcp --dport 18080 \
|
||||
-j DNAT --to-destination <TARGET_PEER_NETBIRD_IP>:8080
|
||||
# Persist via iptables-persistent / netfilter-persistent
|
||||
```
|
||||
|
||||
The clientless device now reaches the service through the routing peer's
|
||||
local IP and the forwarded port:
|
||||
|
||||
```bash
|
||||
curl http://192.168.50.10:18080/
|
||||
```
|
||||
|
||||
The outbound SNAT configured in
|
||||
[Step 3](#step-3-configure-the-outbound-snat) applies to this
|
||||
traffic as well — the target peer still observes the
|
||||
routing peer's NetBird IP as the source.
|
||||
|
||||
Each forwarded service needs its own DNAT rule. This pattern is a good fit
|
||||
for a small number of well-known services; for general overlay access, use
|
||||
the static-route approach in Step 6 instead.
|
||||
@@ -79,7 +79,7 @@ docker run -d --name netbird --cap-add=NET_ADMIN \
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Bake the config into a `ConfigMap`, source the setup key from a `Secret`, and mount both into the pod. Pair this with the liveness, readiness, and startup probes from [Deploy routing peers to a Kubernetes cluster](/use-cases/cloud/routing-peers-and-kubernetes) for a complete deployment.
|
||||
Bake the config into a `ConfigMap`, source the setup key from a `Secret`, and mount both into the pod. Pair this with the liveness, readiness, and startup probes from [Deploy routing peers to a Kubernetes cluster](/use-cases/kubernetes/routing-peers-and-kubernetes) for a complete deployment.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
@@ -150,7 +150,7 @@ For workloads where peers come and go — containers, autoscaling groups, sh
|
||||
netbird status --check startup && echo "registered" || echo "not registered yet"
|
||||
```
|
||||
|
||||
The Kubernetes example in [Deploy routing peers to a Kubernetes cluster](/use-cases/cloud/routing-peers-and-kubernetes#step-4-deploy-the-netbird-agent) wires all three checks into liveness, readiness, and startup probes — a good template for any container-based deployment.
|
||||
The Kubernetes example in [Deploy routing peers to a Kubernetes cluster](/use-cases/kubernetes/routing-peers-and-kubernetes#step-4-deploy-the-netbird-agent) wires all three checks into liveness, readiness, and startup probes — a good template for any container-based deployment.
|
||||
|
||||
### Parseable output
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ Before you start, make sure you have:
|
||||
- A **domain you control** that you can point at the server. You will configure two `A` records: `proxy-domain` and `*.proxy-domain`.
|
||||
|
||||
<Warning>
|
||||
**Port 443 must be reachable from the public internet** for the default `tls-alpn-01` challenge. Let's Encrypt validates over port 443 with a special ALPN protocol. If your environment can't expose port 443 to Let's Encrypt's validation servers, switch to `http-01` (see [TLS configuration](#tls-configuration) below — that mode requires port 80 instead) or supply your own certificates. To run with **no public inbound ports at all**, issue certificates over DNS-01 and serve them statically — see [Private Proxy Without Public Inbound Ports](/manage/reverse-proxy/use-cases/private-no-inbound).
|
||||
**Port 443 must be reachable from the public internet** for the default `tls-alpn-01` challenge. Let's Encrypt validates over port 443 with a special ALPN protocol. If your environment can't expose port 443 to Let's Encrypt's validation servers, switch to `http-01` (see [TLS configuration](#tls-configuration) below — that mode requires port 80 instead) or supply your own certificates. To run with **no public inbound ports at all**, issue certificates over DNS-01 and serve them statically — see [Private Proxy Without Public Inbound Ports](/use-cases/security/private-no-inbound).
|
||||
</Warning>
|
||||
|
||||
## Setup walkthrough
|
||||
@@ -253,7 +253,7 @@ The most common adjustments:
|
||||
| Use Let's Encrypt with port 80 instead of port 443 | `NB_PROXY_ACME_CHALLENGE_TYPE=http-01` |
|
||||
| Provide your own certificate and key | unset `NB_PROXY_ACME_CERTIFICATES`, mount cert + key into `NB_PROXY_CERTIFICATE_DIRECTORY` (defaults: `tls.crt`, `tls.key`) |
|
||||
| Use a wildcard certificate for `*.proxy.company.com` | `NB_PROXY_WILDCARD_CERT_DIR=/certs/wildcard` |
|
||||
| Run with no public inbound ports (issue certs over DNS-01) | see [Private Proxy Without Public Inbound Ports](/manage/reverse-proxy/use-cases/private-no-inbound) |
|
||||
| Run with no public inbound ports (issue certs over DNS-01) | see [Private Proxy Without Public Inbound Ports](/use-cases/security/private-no-inbound) |
|
||||
|
||||
### Sharing certificates across replicas
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ 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.
|
||||
|
||||
Static mode is also how you run a proxy with **no public inbound ports**: issue the certificate out of band over the DNS-01 challenge and serve it here, so certificate issuance never needs port 80 or 443 exposed. See [Private Proxy Without Public Inbound Ports](/manage/reverse-proxy/use-cases/private-no-inbound).
|
||||
Static mode is also how you run a proxy with **no public inbound ports**: issue the certificate out of band over the DNS-01 challenge and serve it here, so certificate issuance never needs port 80 or 443 exposed. See [Private Proxy Without Public Inbound Ports](/use-cases/security/private-no-inbound).
|
||||
|
||||
**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:
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import { Note } from "@/components/mdx"
|
||||
|
||||
export const description =
|
||||
'Run a Bring Your Own Proxy instance in private mode with no public inbound ports by issuing TLS certificates externally over DNS-01 and serving them as static certificates.'
|
||||
|
||||
# Private Proxy Without Public Inbound Ports
|
||||
|
||||
This use case shows how to run a [Bring Your Own Proxy](/manage/reverse-proxy/bring-your-own-proxy) (BYOP) instance that is reachable **only over the NetBird tunnel**, with **no public inbound ports**, while still serving a valid, publicly trusted TLS certificate.
|
||||
|
||||
It applies when you run BYOP as a private cluster with [NetBird-Only Access](/manage/reverse-proxy/authentication#net-bird-only-access-private-services) services and want a fully private deployment, such as a proxy on a locked-down VM whose services are exposed exclusively to peers in your NetBird network.
|
||||
|
||||
## What you'll achieve
|
||||
|
||||
- Services reachable only by peers in your NetBird network, over the WireGuard tunnel.
|
||||
- A valid wildcard TLS certificate served by the proxy, with no certificate warnings.
|
||||
- No public inbound web ports: certificate issuance never requires exposing port 80 or 443 to the internet.
|
||||
|
||||
## Why the built-in ACME doesn't fit
|
||||
|
||||
By default the proxy obtains its own certificates with ACME (Let's Encrypt). Both challenge types it supports validate over an inbound port:
|
||||
|
||||
- `tls-alpn-01` validates on port **443**
|
||||
- `http-01` validates on port **80**
|
||||
|
||||
In either case the certificate authority must reach the proxy from the public internet, which conflicts with a fully private deployment.
|
||||
|
||||
The **DNS-01** challenge avoids this: it proves domain ownership by publishing a TXT record in your DNS zone, so no inbound port is required. The proxy does not perform DNS-01 itself. Instead you **issue the certificate out of band** with any ACME client that supports DNS-01, and run the proxy in **static certificate mode** pointed at the resulting files.
|
||||
|
||||
## Step 1: Configure the proxy for static certificates
|
||||
|
||||
Set these environment variables on the proxy container, alongside the `NB_PROXY_TOKEN` from your [BYOP setup](/manage/reverse-proxy/bring-your-own-proxy#set-up-a-byop-proxy-from-the-api):
|
||||
|
||||
| Variable | Value | Purpose |
|
||||
|---|---|---|
|
||||
| `NB_PROXY_ACME_CERTIFICATES` | `false` | Disable the proxy's own ACME; serve a certificate from disk instead. |
|
||||
| `NB_PROXY_CERTIFICATE_DIRECTORY` | e.g. `/certs` | Directory the proxy reads the certificate and key from. |
|
||||
| `NB_PROXY_PRIVATE` | `true` | Advertise the **Private** capability so the cluster can publish NetBird-Only Access services. |
|
||||
|
||||
The proxy reads the certificate and key as `tls.crt` and `tls.key` in that directory (override with `NB_PROXY_CERTIFICATE_FILE` / `NB_PROXY_CERTIFICATE_KEY_FILE` only if you use different names).
|
||||
|
||||
<Note>
|
||||
This is the standard **static certificate mode** described in [TLS certificate configuration](/manage/reverse-proxy#tls-certificate-configuration); the only BYOP-specific settings are the account-scoped token and the `Private` capability. Configure each service for [NetBird-Only Access](/manage/reverse-proxy/authentication#net-bird-only-access-private-services) on its Authentication tab so it is reachable only from your NetBird network.
|
||||
</Note>
|
||||
|
||||
## Step 2: Issue the certificate over DNS-01
|
||||
|
||||
Use any DNS-01-capable ACME client to issue a wildcard certificate for your proxy domain, then place the result in the certificate directory as `tls.crt` / `tls.key`. A wildcard (`*.proxy.example.com`) works as a single static certificate and covers every service hostname under that domain.
|
||||
|
||||
For example, with [lego](https://go-acme.github.io/lego/):
|
||||
|
||||
```bash
|
||||
# Your DNS provider's API credentials are supplied via environment variables;
|
||||
# see your provider's page in the lego documentation.
|
||||
lego --email you@example.com --dns <provider> \
|
||||
-d '*.proxy.example.com' \
|
||||
--path /certs run
|
||||
```
|
||||
|
||||
Copy or symlink the issued certificate and key to `tls.crt` and `tls.key` in `NB_PROXY_CERTIFICATE_DIRECTORY`.
|
||||
|
||||
Issuance happens entirely through DNS, so the machine running the ACME client needs **outbound** access to your DNS provider's API and to the certificate authority, and no inbound ports.
|
||||
|
||||
## Step 3: Automate renewal
|
||||
|
||||
Run the ACME client on a recurring timer; the common recommendation is twice a day at a randomized time. It re-issues the certificate only when it nears expiry, so frequent runs are cheap and give a renewal plenty of retries before the certificate expires. Each run writes the updated files into the certificate directory.
|
||||
|
||||
The proxy watches the certificate files and **hot-reloads** them when they change, picking up the renewed certificate automatically with no restart and no dropped connections.
|
||||
|
||||
## Verify
|
||||
|
||||
From a NetBird peer whose user is in the service's access group, request the service over the tunnel:
|
||||
|
||||
```bash
|
||||
curl -v https://app.proxy.example.com/
|
||||
```
|
||||
|
||||
`curl` validates the certificate by default, so a successful `200` confirms the served certificate is publicly trusted and matches the hostname (an untrusted certificate makes `curl` fail; don't pass `-k`). The `-v` output shows `SSL certificate verify ok` and the issuer. The same request from outside your NetBird network never reaches the service, since there are no public inbound web ports.
|
||||
|
||||
## Related
|
||||
|
||||
- [Bring Your Own Proxy](/manage/reverse-proxy/bring-your-own-proxy) — full BYOP setup and the account-scoped proxy token.
|
||||
- [TLS certificate configuration](/manage/reverse-proxy#tls-certificate-configuration) — all certificate modes (ACME, static, wildcard).
|
||||
- [NetBird-Only Access](/manage/reverse-proxy/authentication#net-bird-only-access-private-services) — restrict services to your NetBird network.
|
||||
@@ -50,7 +50,7 @@ Access control policies apply to both IPv4 and IPv6 traffic. When a peer has an
|
||||
|
||||
### Exit Nodes
|
||||
|
||||
When an exit node route (`0.0.0.0/0`) is configured and the peer supports IPv6, management automatically creates a matching `::/0` route. See [Exit Nodes](/manage/network-routes/use-cases/exit-nodes#ipv6-support) for details.
|
||||
When an exit node route (`0.0.0.0/0`) is configured and the peer supports IPv6, management automatically creates a matching `::/0` route. See [Exit Nodes](/use-cases/remote-access/exit-nodes#ipv6-support) for details.
|
||||
|
||||
### Network Routes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user