From fcb64e77b4c14f77aedc2ef6e0b1628deb7752de Mon Sep 17 00:00:00 2001 From: John Maguire Date: Tue, 21 Jul 2026 16:28:04 -0400 Subject: [PATCH 1/2] Add guide for running Nebula as non-root --- .../running-nebula-as-non-root/index.mdx | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/guides/running-nebula-as-non-root/index.mdx diff --git a/docs/guides/running-nebula-as-non-root/index.mdx b/docs/guides/running-nebula-as-non-root/index.mdx new file mode 100644 index 0000000..bccde97 --- /dev/null +++ b/docs/guides/running-nebula-as-non-root/index.mdx @@ -0,0 +1,148 @@ +--- +title: Running Nebula as a non-root user +description: + How to run Nebula on Linux as an unprivileged user by granting the CAP_NET_ADMIN capability via systemd or setcap. +summary: + On Linux, Nebula does not need to run as root. This guide shows how to run it as a dedicated unprivileged user by + granting the CAP_NET_ADMIN capability, either through systemd or with file capabilities on the binary. +--- + +# Running Nebula as a non-root user + +Nebula is commonly run as root, but on Linux the privileged operations it performs are creating the tun device, +configuring its address and MTU, and installing routes are all covered by the `CAP_NET_ADMIN` +[capability](https://man7.org/linux/man-pages/man7/capabilities.7.html), so Nebula can run as a dedicated unprivileged +user if the process is granted that capability. Running this way limits the impact of a compromise or bug in Nebula to +what `CAP_NET_ADMIN` allows, rather than full root. + +Everything else Nebula does is unprivileged, with one exception: binding a listener to a port below 1024 additionally +requires `CAP_NET_BIND_SERVICE`. This applies to any of Nebula's listeners you configure on a privileged port, e.g. +[Lighthouse DNS](/docs/guides/using-lighthouse-dns/) on the default DNS port 53, the main UDP listener (e.g. `listen.port: 443` +to traverse restrictive networks), the Prometheus [stats](/docs/config/stats/) endpoint, or the debug +[sshd](/docs/config/sshd/). Outbound-only features such as Graphite stats need nothing extra. + +:::note + +This only applies to Linux. On macOS and Windows, creating the tun device requires root/Administrator, and there is no +equivalent capability mechanism. If you only need a lighthouse or relay on those platforms, you can set +[`tun.disabled: true`](/docs/config/tun/#tundisabled) to run without a tun device (and therefore without root). + +::: + +## Create a user for Nebula + +Create a system user and give it ownership of the config directory. The private key and CA material should not be +readable by other users: + +```bash +sudo useradd --system --shell /usr/sbin/nologin nebula +sudo chown -R nebula:nebula /etc/nebula +sudo chmod 0700 /etc/nebula +``` + +## Option 1: systemd ambient capabilities (recommended) + +If you manage Nebula with systemd, add `User`, `Group`, and the two capability directives to the `[Service]` section of +your unit. This is the [example unit](https://github.com/slackhq/nebula/blob/master/examples/service_scripts/nebula.service) +from the Nebula repository with those four lines added: + +```systemd +[Unit] +Description=Nebula overlay networking tool +Wants=basic.target network-online.target nss-lookup.target time-sync.target +After=basic.target network.target network-online.target +Before=sshd.service + +[Service] +Type=notify +NotifyAccess=main +SyslogIdentifier=nebula +User=nebula +Group=nebula +CapabilityBoundingSet=CAP_NET_ADMIN +AmbientCapabilities=CAP_NET_ADMIN +ExecReload=/bin/kill -HUP $MAINPID +ExecStart=/usr/local/bin/nebula -config /etc/nebula/config.yml +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +`AmbientCapabilities` is what grants `CAP_NET_ADMIN` to the non-root process. `CapabilityBoundingSet` additionally +drops every other capability from the service, so even a compromised process cannot regain them. + +Reload and restart: + +```bash +sudo systemctl daemon-reload +sudo systemctl restart nebula +``` + +If any listener (Lighthouse DNS, the main UDP port, stats, sshd) binds below port 1024, list both capabilities: + +```systemd +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE +``` + +## Option 2: file capabilities with setcap + +If you are not using systemd, you can attach the capability to the binary itself and run it directly as the unprivileged +user: + +```bash +sudo setcap cap_net_admin+ep /usr/local/bin/nebula +``` + +If any listener binds below port 1024: + +```bash +sudo setcap 'cap_net_admin,cap_net_bind_service+ep' /usr/local/bin/nebula +``` + +:::warning + +File capabilities apply to anyone who can execute the binary — any local user could then create tun devices and modify +routes by running it. Prefer the systemd approach where possible, or restrict execute permission on the binary to the +nebula user. Note that the capability is attached to the file's extended attributes, so it must be re-applied after +upgrading or replacing the binary. + +::: + +## Verifying + +Check that the process is running as the nebula user with only the expected capabilities: + +```bash +$ ps -o user,cmd -C nebula +USER CMD +nebula /usr/local/bin/nebula -config /etc/nebula/config.yml + +$ grep CapEff /proc/$(pidof nebula)/status +CapEff: 0000000000001000 +``` + +`0000000000001000` decodes to exactly `cap_net_admin` (`capsh --decode=0000000000001000`); with +`CAP_NET_BIND_SERVICE` added it is `0000000000001400`. Confirm the interface and any +[`unsafe_routes`](/docs/guides/unsafe_routes/) are present with `ip link show nebula1` and `ip route`. + +## Troubleshooting + +**`Failed to get a tun/tap device ... operation not permitted`** — the process does not have `CAP_NET_ADMIN`. Confirm +the unit's `AmbientCapabilities` line (or `getcap` output on the binary) and that you restarted the service after +`systemctl daemon-reload`. Nebula exits immediately on this error. + +**`bind: permission denied`** — a listener (here Lighthouse DNS: `Failed to start server: listen udp 0.0.0.0:53: bind: +permission denied`) is configured on a privileged port but the process only has `CAP_NET_ADMIN`; add +`CAP_NET_BIND_SERVICE`. Note that for the DNS responder this error is +_non-fatal_: the service stays running with a working tun device and only the DNS responder is down, so watch the logs +rather than the service state. + +**`bind: address already in use` on port 53** — the capability is working, but something else already owns the port. On +distributions with `systemd-resolved`, its stub listener on `127.0.0.53:53` conflicts with binding `0.0.0.0:53`; bind +Nebula's DNS to a specific address or disable the stub listener. + +**`Failed to set tun tx queue length: operation not permitted`** — logged when Nebula runs inside a container +(LXC/Incus/Docker) where the tx queue length cannot be changed even with `CAP_NET_ADMIN`. It is harmless; the interface +still comes up. From a346099f7c4d454d6a02a6593a6cbbd9af643ee9 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Tue, 21 Jul 2026 16:56:49 -0400 Subject: [PATCH 2/2] Make guides more consistent, generally --- docs/config/tun.mdx | 2 +- docs/guides/debug-ssh-commands/index.mdx | 1 + docs/guides/quick-start/index.mdx | 2 +- .../rotating-certificate-authority/index.mdx | 3 +- .../running-nebula-as-non-root/index.mdx | 30 ++++++++++--------- .../index.mdx | 3 +- docs/guides/unsafe_routes/index.mdx | 5 ++-- .../upgrade-to-cert-v2-and-ipv6/index.mdx | 1 + docs/guides/using-lighthouse-dns/index.mdx | 3 +- docs/guides/viewing-nebula-logs/index.mdx | 5 ++-- 10 files changed, 32 insertions(+), 23 deletions(-) diff --git a/docs/config/tun.mdx b/docs/config/tun.mdx index 648b0ec..38d7f65 100644 --- a/docs/config/tun.mdx +++ b/docs/config/tun.mdx @@ -102,7 +102,7 @@ tun: install: true # controls whether this route is installed in the systems routing table. ``` -For more information, see the [Extend network access beyond overlay hosts](/docs/guides/unsafe_routes/) guide. +For more information, see the [Extending network access beyond overlay hosts](/docs/guides/unsafe_routes/) guide. ### ECMP support for `unsafe_routes` diff --git a/docs/guides/debug-ssh-commands/index.mdx b/docs/guides/debug-ssh-commands/index.mdx index 13c286b..835ff14 100644 --- a/docs/guides/debug-ssh-commands/index.mdx +++ b/docs/guides/debug-ssh-commands/index.mdx @@ -5,6 +5,7 @@ description: summary: This guide describes useful commands built into the SSH server accessible over nebula, which can allow debugging network connectivity for the nebula host. +sidebar_position: 7 --- # Debugging with Nebula SSH commands diff --git a/docs/guides/quick-start/index.mdx b/docs/guides/quick-start/index.mdx index 2edbb87..4a47dc8 100644 --- a/docs/guides/quick-start/index.mdx +++ b/docs/guides/quick-start/index.mdx @@ -1,5 +1,5 @@ --- -title: Quick Start +title: Quick start description: How to create your first overlay network using a Certificate Authority, Lighthouse, and Hosts summary: This section will walk you through setting up a simple nebula network for testing. The examples will need to be diff --git a/docs/guides/rotating-certificate-authority/index.mdx b/docs/guides/rotating-certificate-authority/index.mdx index ebefa33..0ae22f7 100644 --- a/docs/guides/rotating-certificate-authority/index.mdx +++ b/docs/guides/rotating-certificate-authority/index.mdx @@ -1,10 +1,11 @@ --- -title: Rotating a Certificate Authority +title: Rotating a certificate authority description: How to rotate an expiring Nebula certificate authority without downtime. summary: This guide will teach you how to migrate from an expiring certificate authority by creating a new certificate authority, updating your device's Nebula config to trust the new authority, signing new host certificates, and removing the old certificate authority from the trust bundle. +sidebar_position: 4 --- # How to rotate to a new certificate authority diff --git a/docs/guides/running-nebula-as-non-root/index.mdx b/docs/guides/running-nebula-as-non-root/index.mdx index bccde97..d5c0ef5 100644 --- a/docs/guides/running-nebula-as-non-root/index.mdx +++ b/docs/guides/running-nebula-as-non-root/index.mdx @@ -5,6 +5,7 @@ description: summary: On Linux, Nebula does not need to run as root. This guide shows how to run it as a dedicated unprivileged user by granting the CAP_NET_ADMIN capability, either through systemd or with file capabilities on the binary. +sidebar_position: 2 --- # Running Nebula as a non-root user @@ -17,8 +18,8 @@ what `CAP_NET_ADMIN` allows, rather than full root. Everything else Nebula does is unprivileged, with one exception: binding a listener to a port below 1024 additionally requires `CAP_NET_BIND_SERVICE`. This applies to any of Nebula's listeners you configure on a privileged port, e.g. -[Lighthouse DNS](/docs/guides/using-lighthouse-dns/) on the default DNS port 53, the main UDP listener (e.g. `listen.port: 443` -to traverse restrictive networks), the Prometheus [stats](/docs/config/stats/) endpoint, or the debug +[Lighthouse DNS](/docs/guides/using-lighthouse-dns/) on the default DNS port 53, the main UDP listener (e.g. +`listen.port: 443` to traverse restrictive networks), the Prometheus [stats](/docs/config/stats/) endpoint, or the debug [sshd](/docs/config/sshd/). Outbound-only features such as Graphite stats need nothing extra. :::note @@ -43,8 +44,9 @@ sudo chmod 0700 /etc/nebula ## Option 1: systemd ambient capabilities (recommended) If you manage Nebula with systemd, add `User`, `Group`, and the two capability directives to the `[Service]` section of -your unit. This is the [example unit](https://github.com/slackhq/nebula/blob/master/examples/service_scripts/nebula.service) -from the Nebula repository with those four lines added: +your unit. This is the +[example unit](https://github.com/slackhq/nebula/blob/master/examples/service_scripts/nebula.service) from the Nebula +repository with those four lines added: ```systemd [Unit] @@ -69,8 +71,8 @@ Restart=always WantedBy=multi-user.target ``` -`AmbientCapabilities` is what grants `CAP_NET_ADMIN` to the non-root process. `CapabilityBoundingSet` additionally -drops every other capability from the service, so even a compromised process cannot regain them. +`AmbientCapabilities` is what grants `CAP_NET_ADMIN` to the non-root process. `CapabilityBoundingSet` additionally drops +every other capability from the service, so even a compromised process cannot regain them. Reload and restart: @@ -123,9 +125,9 @@ $ grep CapEff /proc/$(pidof nebula)/status CapEff: 0000000000001000 ``` -`0000000000001000` decodes to exactly `cap_net_admin` (`capsh --decode=0000000000001000`); with -`CAP_NET_BIND_SERVICE` added it is `0000000000001400`. Confirm the interface and any -[`unsafe_routes`](/docs/guides/unsafe_routes/) are present with `ip link show nebula1` and `ip route`. +`0000000000001000` decodes to exactly `cap_net_admin` (`capsh --decode=0000000000001000`); with `CAP_NET_BIND_SERVICE` +added it is `0000000000001400`. Confirm the interface and any [`unsafe_routes`](/docs/guides/unsafe_routes/) are present +with `ip link show nebula1` and `ip route`. ## Troubleshooting @@ -133,11 +135,11 @@ CapEff: 0000000000001000 the unit's `AmbientCapabilities` line (or `getcap` output on the binary) and that you restarted the service after `systemctl daemon-reload`. Nebula exits immediately on this error. -**`bind: permission denied`** — a listener (here Lighthouse DNS: `Failed to start server: listen udp 0.0.0.0:53: bind: -permission denied`) is configured on a privileged port but the process only has `CAP_NET_ADMIN`; add -`CAP_NET_BIND_SERVICE`. Note that for the DNS responder this error is -_non-fatal_: the service stays running with a working tun device and only the DNS responder is down, so watch the logs -rather than the service state. +**`bind: permission denied`** — a listener (here Lighthouse DNS: +`Failed to start server: listen udp 0.0.0.0:53: bind: permission denied`) is configured on a privileged port but the +process only has `CAP_NET_ADMIN`; add `CAP_NET_BIND_SERVICE`. Note that for the DNS responder this error is _non-fatal_: +the service stays running with a working tun device and only the DNS responder is down, so watch the logs rather than +the service state. **`bind: address already in use` on port 53** — the capability is working, but something else already owns the port. On distributions with `systemd-resolved`, its stub listener on `127.0.0.53:53` conflicts with binding `0.0.0.0:53`; bind diff --git a/docs/guides/sign-certificates-with-public-keys/index.mdx b/docs/guides/sign-certificates-with-public-keys/index.mdx index 64b7d3f..4359217 100644 --- a/docs/guides/sign-certificates-with-public-keys/index.mdx +++ b/docs/guides/sign-certificates-with-public-keys/index.mdx @@ -1,9 +1,10 @@ --- -title: Signing a Certificate Without a Private Key +title: Signing a certificate without a private key description: How to sign Nebula certificates without copying private keys across devices. summary: After reading this guide you will be able to create public/private keypairs on devices you wish to add to the Nebula network and generate certificates for them using only the public key. +sidebar_position: 3 --- # How to use public keys to create signed certificates diff --git a/docs/guides/unsafe_routes/index.mdx b/docs/guides/unsafe_routes/index.mdx index 4aecce6..17f8b10 100644 --- a/docs/guides/unsafe_routes/index.mdx +++ b/docs/guides/unsafe_routes/index.mdx @@ -1,14 +1,15 @@ --- -title: Extend network access beyond overlay hosts +title: Extending network access beyond overlay hosts description: Configure Nebula unsafe_routes to route traffic through overlay hosts and reach devices that cannot run Nebula directly. summary: This guide explains how to configure Nebula to route traffic destined for a specific subnet through a specific overlay network host, which is useful for accessing hosts that cannot be modified to run Nebula. +sidebar_position: 6 --- -# Extend network access beyond overlay hosts +# Extending network access beyond overlay hosts This guide explains how to configure Nebula to route traffic destined for a specific subnet _through_ a specific overlay network host using Nebula's `unsafe_routes` feature. diff --git a/docs/guides/upgrade-to-cert-v2-and-ipv6/index.mdx b/docs/guides/upgrade-to-cert-v2-and-ipv6/index.mdx index f805a8e..b2c549b 100644 --- a/docs/guides/upgrade-to-cert-v2-and-ipv6/index.mdx +++ b/docs/guides/upgrade-to-cert-v2-and-ipv6/index.mdx @@ -5,6 +5,7 @@ description: addresses. summary: This guide describes how to upgrade an existing nebula network to the v2 certificate format and enable IPv6 addresses. +sidebar_position: 8 --- # Upgrading a Nebula network to IPv6 overlay addresses diff --git a/docs/guides/using-lighthouse-dns/index.mdx b/docs/guides/using-lighthouse-dns/index.mdx index 6e9eb68..3a5c509 100644 --- a/docs/guides/using-lighthouse-dns/index.mdx +++ b/docs/guides/using-lighthouse-dns/index.mdx @@ -2,9 +2,10 @@ title: Using Lighthouse DNS with Nebula description: Configure Nebula's experimental built-in DNS server on Lighthouse hosts to resolve overlay network hostnames. +sidebar_position: 5 --- -# Using Experimental Lighthouse DNS with Nebula +# Using Lighthouse DNS with Nebula :::warning diff --git a/docs/guides/viewing-nebula-logs/index.mdx b/docs/guides/viewing-nebula-logs/index.mdx index 923f02f..ad09690 100644 --- a/docs/guides/viewing-nebula-logs/index.mdx +++ b/docs/guides/viewing-nebula-logs/index.mdx @@ -1,11 +1,12 @@ --- -title: Viewing Nebula Logs +title: Viewing Nebula logs description: How to view Nebula logs on Linux, macOS, Windows, iOS, and Android for troubleshooting and monitoring. +sidebar_position: 9 --- import ThemedImage from '@theme/ThemedImage'; -# Viewing Nebula Logs +# Viewing Nebula logs This guide explains how to view logs for Nebula in each of the supported platforms. Please note that these instructions are approximations as there are many ways that Nebula can be installed.