Files
netbird-docs/src/pages/client/environment-variables.mdx
T
Riccardo Manfrin cb5813d1df Document that a primary nameserver is exclusive on Windows (#950)
* docs: document that a primary nameserver is exclusive on Windows

A peer with a primary nameserver now gets a Name Resolution Policy Table rule
covering every namespace, so all resolution goes through NetBird and nowhere
else. Without it Windows queries every adapter's resolvers in parallel and keeps
whichever answer arrives first, which leaks queries to the local network and lets
another resolver answer for a name NetBird is authoritative for.

Two consequences worth knowing before it surprises someone:

- Zones only the local network resolves stop working while connected, unless
  they are declared as match domains. A more specific rule takes precedence, so
  declaring the zone is the fix. `.local` is exempt, so multicast DNS is
  unaffected.
- Short names depend on which adapter's suffix Windows tries first, and it stops
  at the first "no such name" rather than continuing down the list. On
  domain-joined machines the machine's own domain wins that first attempt, so a
  short name can fail while its fully qualified form resolves.

Placed next to the existing macOS note in the same section, since both are about
what a primary nameserver does beyond catching unmatched queries, and next to the
existing warning about emptying match domains, which the suffix caveat explains
the other half of.

Also documents NB_USE_LEGACY_DNS_RESOLUTION, which restores the old behaviour on
a peer.

* docs: correct how Windows expands short names, and say from which version

Two fixes to the notes added in the previous commit.

The short-name mechanism was described wrongly. Windows does not stop at the
first suffix that misses: it walks the whole suffix list of the preferred
interface, and what it will not do is fall through to another interface's
suffixes. Measured on a Windows 11 machine — with NetBird's adapter preferred, a
list of {fritz.box, netbird.cloud} resolves a name that only exists under the
second entry; with the metric raised so the physical adapter wins, the same name
fails because only that adapter's single suffix is ever tried. The practical
advice changes with it: declaring the local zone with search domains enabled puts
both suffixes in one list, which is what makes short names work either way.

Both notes now say the exclusive behaviour arrives in client v0.78.0 and what
earlier clients did instead, so the page reads correctly for someone still on
0.77, and the environment variable is marked with the version that introduces it.

* docs: say that exclusive resolution is what breaks short names on Windows

The suffix-search behaviour is not Windows' own: without the catch-all NRPT
rule Windows keeps searching the other adapters' suffix lists, and the short
name resolves. Gate the note to v0.78.0 and point at it from the exclusivity
note, so both texts agree on what the change costs.
2026-09-04 11:43:16 +02:00

157 lines
16 KiB
Plaintext

# Client Environment Variables
The NetBird client supports environment variables for advanced configuration. These are separate from the CLI flag environment variables (like `NB_LOG_LEVEL`) which are described in the [CLI reference](/get-started/cli#environment-variables).
## Setting environment variables
Environment variables must be set on the **daemon process**, not the CLI. When running NetBird as a system service, use `--service-env` to persist them:
```shell
# Set during install
sudo netbird service install --service-env NB_WG_KERNEL_DISABLED=true
# Or reconfigure a running service
sudo netbird service reconfigure --service-env NB_WG_KERNEL_DISABLED=true
# Multiple variables
sudo netbird service install --service-env NB_LOG_LEVEL=debug,NB_USE_LEGACY_ROUTING=true
```
When running in foreground mode, set them in the shell before starting:
```shell
NB_WG_KERNEL_DISABLED=true netbird up --foreground-mode
```
<Note>
To clear all saved service parameters (including env vars), run `sudo netbird service reset-params` followed by `sudo netbird service reconfigure`.
</Note>
## Networking and routing
| Variable | Platform | Description |
|---|---|---|
| `NB_USE_LEGACY_ROUTING` | Linux | Bypass the fwmark/ip-rule based routing and fall back to the simpler pre-0.26 routing method. Useful when exit nodes cause connectivity issues due to rp_filter or missing sysctl settings. |
| `NB_SKIP_SOCKET_MARK` | Linux | Backward-compatibility alias for `NB_USE_LEGACY_ROUTING`. |
| `NB_DISABLE_CUSTOM_ROUTING` | All | Revert to the routing behavior from before exit node support was added. No exclusion routes or fwmark-based socket routing will be used; all dialers and listeners fall back to plain `net.Dial`/`net.Listen`. Routes with a prefix of /7 or larger (e.g. default routes, 0.0.0.0/0) will be rejected. |
| `NB_ROUTE_PROTO_FLAG` | macOS, BSD | Set a custom route flag on routes the client adds to the routing table. Accepted values: `2` (RTF_PROTO2) or `3` (RTF_PROTO3); defaults to RTF_PROTO1. Not used on Linux (Linux uses netlink with its own protocol field). |
| `NB_DISABLE_ROUTE_CACHE` | Windows | Disable the 2-second cache on Windows routing table lookups. The client reads the OS routing table (via Win32 API) when adding or removing routes; without the cache, each operation triggers a fresh read. Only needed for debugging route conflicts. |
| `NB_FWMARK_BASE` | Linux | Move the netfilter mark range the client uses (default base `0x1BD00`, covering `0x1BD00`-`0x1BD0FF`). Set this when other software on the host claims bits the NetBird marks use, so its rules act on NetBird traffic. The value is the base of the range, decimal or `0x`-prefixed, and the low byte identifies the individual mark, so it has to be left free: `NB_FWMARK_BASE=0x11000` puts the marks at `0x11000`-`0x110FF`. A value that is zero, larger than 32 bits, or has a bit set in its low byte is rejected with a warning in the log and the default range is used. |
Container network plugins, CNIs and other VPNs claim bits of the mark space for themselves. When one of them has a rule matching a bit that a NetBird mark also sets, that rule acts on NetBird traffic, which shows up as traffic being dropped, masqueraded, or routed elsewhere. `NB_FWMARK_BASE` moves the whole NetBird range out of the way.
<Warning>
The client removes the routing rule for its mark range on shutdown. If you change `NB_FWMARK_BASE` while the client was not shut down gracefully (killed, crashed, host reset), the rule for the previous range stays behind and has to be removed by hand, otherwise traffic keeps being sent to the NetBird routing table:
```shell
# Find the leftover rule, it names the mark of the previous range
ip rule show
ip -6 rule show
# Remove it for both families, with the mark the rules above named
# (0x1bd00 here is the default base, use the previous one if it was custom)
sudo ip -4 rule del not from all fwmark 0x1bd00 lookup netbird priority 110
sudo ip -6 rule del not from all fwmark 0x1bd00 lookup netbird priority 110
```
</Warning>
## WireGuard and interface
| Variable | Platform | Description |
|---|---|---|
| `NB_WG_KERNEL_DISABLED` | Linux | Skip loading the WireGuard kernel module and run entirely in userspace (wireguard-go). Use this when the kernel module is broken, missing, or conflicts with other software. |
| `NB_WG_DEBUG` | All | Set to `true` to print low-level WireGuard protocol messages (handshakes, keypairs, timers) to the log. Very verbose. |
| `NB_DISABLE_EBPF_WG_PROXY` | Linux | Disable the eBPF-based proxy that intercepts WireGuard UDP traffic and fall back to the classic UDP port proxy. |
| `NB_USE_NETSTACK_MODE` | All | Run WireGuard on top of a userspace TCP/IP stack (gVisor netstack) instead of a TUN device. Required for environments without TUN support (e.g. unprivileged containers). |
| `NB_NETSTACK_SKIP_PROXY` | All | When using netstack mode, do not start the built-in SOCKS5 proxy that exposes the WireGuard network to local applications. |
| `NB_SOCKS5_LISTENER_PORT` | All | Override the port the netstack SOCKS5 proxy listens on (default: `1080`). Only relevant when netstack mode is active. |
| `NB_SOCKS5_LISTENER_ADDRESS` | All | Override the host/IP the netstack SOCKS5 proxy binds to (default: `127.0.0.1`). The proxy is unauthenticated and meant for local applications only, so it listens on loopback. Set this (e.g. to `0.0.0.0`) only when the proxy must be reachable from other hosts, such as a container gateway — this exposes an unauthenticated proxy on that address. Only relevant when netstack mode is active. |
## Firewall
| Variable | Platform | Description |
|---|---|---|
| `NB_SKIP_NFTABLES_CHECK` | Linux | Do not probe for nftables support at startup; go straight to the iptables backend. Useful on systems where nftables is installed but non-functional (e.g. missing kernel modules). |
| `NB_NFTABLES_TABLE` | Linux | Name of the nftables table the client creates for ACL rules (default: `netbird`). Change this if the default name conflicts with existing firewall configuration. |
| `NB_DISABLE_CONNTRACK` | All | Turn off the stateful connection tracker in the userspace packet filter. With conntrack enabled (default), inbound rules for return traffic sent by management are ignored because conntrack handles them automatically. Disabling conntrack means those inbound rules will be applied explicitly instead. |
| `NB_DISABLE_USERSPACE_ROUTING` | All | Prevent the userspace packet filter from forwarding packets between interfaces. Routing rules from the management server will be ignored when this is set. |
| `NB_DISABLE_MSS_CLAMPING` | All | Stop the userspace filter from rewriting TCP SYN/SYN-ACK MSS options to fit the WireGuard MTU. May cause path-MTU black holes if disabled. |
| `NB_FORCE_USERSPACE_ROUTER` | All | Force packet forwarding through the userspace router even when a native firewall backend (nftables/iptables) is available. Normally, the presence of a native backend causes the client to delegate route forwarding to the kernel. This flag overrides that: the native backend still handles ACL rules, but routed packets are forwarded by the userspace filter instead. On macOS, Windows, and netstack mode the userspace router is always used regardless of this setting. |
| `NB_ENABLE_LOCAL_FORWARDING` | All | Allow the userspace filter to forward packets destined for local addresses (not just routed subnets). Off by default to prevent unexpected local service exposure. |
| `NB_ENABLE_NETSTACK_LOCAL_FORWARDING` | All | Same as `NB_ENABLE_LOCAL_FORWARDING` but applies only when running in netstack mode. Takes precedence over the general setting when both are set. |
| `NB_USPFILTER_LOG_BUFFER` | All | Number of log messages the userspace packet filter can queue before dropping (default: `1000`). Increase this on high-throughput nodes to avoid losing firewall log entries. |
## ICE and connectivity
| Variable | Platform | Description |
|---|---|---|
| `NB_FORCE_RELAY` | All | Skip direct connectivity entirely: the client will not start the ICE listener or attempt peer-to-peer connections. All traffic goes through relay servers. Useful for strict egress-only environments. |
| `NB_ICE_KEEP_ALIVE_INTERVAL_SEC` | All | How often (in seconds) ICE sends keepalive packets to maintain NAT bindings and detect connection liveness (default: `4`). |
| `NB_ICE_DISCONNECTED_TIMEOUT_SEC` | All | Seconds of silence before ICE marks a connection as disconnected and starts recovery (default: `6`). |
| `NB_ICE_FAILED_TIMEOUT_SEC` | All | Seconds of silence before ICE gives up on the connection entirely and falls back to relay (default: `6`). |
| `NB_ICE_RELAY_ACCEPTANCE_MIN_WAIT_SEC` | All | Minimum seconds ICE waits for a direct (P2P) candidate before accepting a relay candidate. Higher values give direct connections more time to succeed at the cost of slower initial connection (default: `2`). |
| `NB_ICE_MONITOR_PERIOD` | All | Interval between ICE connection health checks that verify handshake freshness and trigger reconnection if needed (Go duration, default: `5m`). |
| `NB_LAZY_CONN` | All | Local lazy-connection override. `on` forces lazy connections enabled, `off` forces them disabled, and leaving it unset defers to the Management or MDM setting. Overrides MDM when both are configured. Replaces the removed `NB_ENABLE_EXPERIMENTAL_LAZY_CONN`; the deprecated `--enable-lazy-connection` CLI flag is inert. |
| `NB_LAZY_CONN_INACTIVITY_THRESHOLD` | All | How long a lazy connection can be idle before it is torn down (Go duration, default: `15m`). Only applies when lazy connections are enabled. |
## DNS
| Variable | Platform | Description |
|---|---|---|
| `NB_DNS_FORWARDER_PORT` | All | Override the port the internal DNS forwarder binds to for handling DNS routes received from clients (default: `22054`). The forwarder is separate from the local resolver. |
| `NB_SKIP_DNS_PROBE` | All | Skip the startup check that sends a test query to the local resolver to verify it is reachable. Set this if the probe causes delays (e.g. in air-gapped networks). |
| `NB_DNS_LAZY_WARMUP_TIMEOUT` | All | Per-query budget for waking an idle peer when the local resolver returns one of its A or AAAA records (Go duration, default: `2s`). The value must be positive; invalid, zero, or negative values use the default. |
| `NB_USE_LEGACY_DNS_RESOLUTION` | Windows | Available from client v0.78.0. Go back to only setting the NetBird address as the tunnel adapter's nameserver, leaving Windows free to query the other adapters' resolvers in parallel. By default, a peer with a primary nameserver also gets a Name Resolution Policy Table rule that sends every query to the NetBird resolver and nowhere else. Set this if a zone that only the local network resolves has to stay reachable while connected and cannot be declared as a match domain — it also brings back the query leak and the non-deterministic resolution the rule prevents. |
| `NB_UNCLEAN_SHUTDOWN_RESOLV_FILE` | Linux, FreeBSD | Custom file path to store a backup of `/etc/resolv.conf` before the client modifies it. Used to restore the original on next startup if the client crashed without cleaning up (default: `<state-dir>/resolv.conf`, i.e. `/var/lib/netbird/resolv.conf` on Linux, `/var/db/netbird/resolv.conf` on FreeBSD). |
## Connection retry
These control the exponential backoff when the client loses its connection to the management or signal server.
| Variable | Platform | Description |
|---|---|---|
| `NB_CONN_RETRY_INTERVAL_TIME` | All | Initial wait time before the first reconnection attempt (Go duration, e.g. `5s`). |
| `NB_CONN_MAX_RETRY_INTERVAL_TIME` | All | Upper bound on the backoff interval; retries will never wait longer than this (Go duration). |
| `NB_CONN_MAX_RETRY_TIME_TIME` | All | Total time the client will keep retrying before giving up and reporting a persistent failure (Go duration). Note: the double `_TIME` suffix is intentional and matches the variable name in the source code. |
| `NB_CONN_RETRY_MULTIPLIER` | All | Factor by which the retry interval grows after each attempt (float, e.g. `1.7`). |
## SSH
| Variable | Platform | Description |
|---|---|---|
| `NB_DISABLE_SSH_CONFIG` | All | Prevent the client from writing NetBird peer entries into the system SSH config directory (`/etc/ssh/ssh_config.d/99-netbird.conf` on Unix, `%PROGRAMDATA%\ssh\ssh_config.d\99-netbird.conf` on Windows). By default, the client adds `Host` blocks so you can `ssh peer-name` without specifying the IP. |
| `NB_FORCE_SSH_CONFIG` | All | Write the SSH config entries even when the peer count exceeds the default limit of 200. Without this, the client skips SSH config generation for large networks to avoid slow file writes. |
## Relay
| Variable | Platform | Description |
|---|---|---|
| `NB_RELAY_HC_ATTEMPT_THRESHOLD` | All | Number of consecutive failed WebSocket pings before the client considers a relay server unreachable and switches to a different one (default: `1`). |
## Management
| Variable | Platform | Description |
|---|---|---|
| `NB_MANAGEMENT_GRPC_MAX_MSG_SIZE` | All | Maximum size (in bytes) of a single gRPC message from the management server. Increase this when the network map (peers, firewall rules, routes, DNS config) exceeds the default 4 MB gRPC limit. |
## Logging
| Variable | Platform | Description |
|---|---|---|
| `NB_LOG_FORMAT` | All | Override the log output format. Accepted values: `json` (one JSON object per line) or `syslog` (compact format used when logging to syslog). Anything else falls back to the default human-readable text formatter. The `syslog` value is also selected automatically when the log destination is set to `syslog`. |
| `NB_LOG_MAX_SIZE_MB` | All | Maximum size in megabytes of a single log file before NetBird's built-in rotation triggers (default: `15`). Only effective when the built-in rotation is active, see `NB_LOG_DISABLE_ROTATION` and [Log rotation](/help/troubleshooting-client#log-rotation). |
| `NB_LOG_DISABLE_ROTATION` | All | Set to `true` to disable NetBird's built-in log rotation. NetBird will write to the configured log file directly and leave rotation to an external tool (e.g. system `logrotate` on Linux). On Linux, NetBird also auto-disables its own rotation when it detects a `logrotate` config that mentions `netbird`, this variable lets you force the same behavior on other platforms or when the auto-detection misses your config. Also see [Log rotation troubleshooting](/help/troubleshooting-client#log-rotation). |
## Other
| Variable | Platform | Description |
|---|---|---|
| `NB_STATE_DIR` | All | Override the directory where the client stores persistent state files (config, state.json, WireGuard keys). Defaults to `/var/lib/netbird` on Linux/macOS, `/var/db/netbird` on FreeBSD, `%PROGRAMDATA%\Netbird` on Windows. |
| `NB_DNS_STATE_FILE` | All | Override the path to the client state file (`state.json`). Despite the name, this is not DNS-specific: it stores all shutdown/recovery state including DNS settings, SSH config, routes, and auto-update progress. The default path is per-profile (e.g. `/var/lib/netbird/state.json` for the default profile). Setting this bypasses per-profile state isolation. Primarily used by the embedded client API (`embed.Options.StatePath`). |
| `NB_ROSENPASS_LOG_LEVEL` | All | Log level for the Rosenpass post-quantum key exchange subprocess. Accepted values: `debug`, `info`, `warn`, `error` (default: `info`). Separate from the main client log level. |
| `NB_AUTO_UPDATE_DRY_RUN` | All | Set to `true` to run the auto-update check and download steps without actually replacing the binary. Useful for testing update infrastructure. |
| `NB_PPROF_ADDR` | All | Start a Go pprof HTTP endpoint at this address (e.g. `localhost:6060`). For profiling CPU, memory, and goroutine usage in production. |
| `NB_METRICS_PUSH_ENABLED` | All | Set to `true` to enable periodic push of client telemetry (connection quality, peer counts) to a metrics server. Disabled by default. |
| `NB_METRICS_INTERVAL` | All | How often to push metrics when enabled (Go duration, e.g. `60s`). |
| `NB_METRICS_SERVER_URL` | All | URL of the metrics collection server. Only needed when overriding the built-in default. |
| `NB_METRICS_CONFIG_URL` | All | URL to fetch remote metrics configuration (which metrics to collect, sampling rates). Only needed when overriding the built-in default. |