From 31a54a7bb12dad7d49f0721924d8dcce2ad5f640 Mon Sep 17 00:00:00 2001 From: shuuri-labs <61762328+shuuri-labs@users.noreply.github.com> Date: Thu, 30 Apr 2026 17:28:04 +0200 Subject: [PATCH] Add NetBird VPN setup guide (#1659) * Add NetBird VPN setup guide for PiKVM Document the full setup process for running NetBird on PiKVM's read-only filesystem, including overlayfs configuration, systemd service modifications, device registration (setup key and SSO), state persistence, and common troubleshooting steps. * fix: replace curl|bash install with AUR package build Address maintainer review: use git clone + makepkg under kvmd-webterm to build netbird-bin from AUR instead of piping install script to sh. Also replace overlayfs with tmpfs + bind mount since PiKVM's kernel lacks the overlay module, and update all systemd references to use the AUR package's template unit (netbird@.service). --- docs/netbird.md | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 334 insertions(+) create mode 100644 docs/netbird.md diff --git a/docs/netbird.md b/docs/netbird.md new file mode 100644 index 00000000..de1c38fe --- /dev/null +++ b/docs/netbird.md @@ -0,0 +1,333 @@ +--- +title: NetBird VPN +description: How to configure the access to your PiKVM using NetBird VPN +--- + +[NetBird](https://netbird.io/) can be used to access PiKVM from the Internet +if configuring [port forwarding](port_forwarding.md) is not possible or more +security is desired. NetBird is an open-source, self-hostable WireGuard-based mesh +VPN that connects devices peer-to-peer without a central gateway. NetBird also offers a free (for private use) +hosted management service. + +Because PiKVM's root filesystem is read-only, NetBird requires an overlay +filesystem so it can write runtime state without modifying the underlying disk. + +----- + +## Setting up the overlay + +The NetBird client stores its state in `/var/lib/netbird`. On PiKVM this path must be +writable at runtime, so we mount an overlay backed by tmpfs over a persistent +copy of the state. + +1. Switch to read-write mode and create the persistent state directory: + + ```console + [root@pikvm ~]# rw + [root@pikvm ~]# mkdir -p /root/netbird-state + ``` + +2. Create the helper script. Save as `/usr/local/bin/setup-netbird-overlay.sh`: + + ```bash + #!/bin/bash + set -e + + # Mount a tmpfs for writable NetBird state + mkdir -p /tmp/netbird-state + mount -t tmpfs tmpfs /tmp/netbird-state + + # Copy persistent state into the writable tmpfs + if [ -d /root/netbird-state ]; then + cp -a /root/netbird-state/. /tmp/netbird-state/ + fi + + # Bind mount over /var/lib/netbird so NetBird sees the writable copy + mkdir -p /var/lib/netbird + mountpoint -q /var/lib/netbird && umount /var/lib/netbird || true + mount --bind /tmp/netbird-state /var/lib/netbird + ``` + + Make it executable: + + ```console + [root@pikvm ~]# chmod +x /usr/local/bin/setup-netbird-overlay.sh + ``` + +3. Create a systemd unit to run the setup before NetBird starts and save + state back on stop. Save as `/etc/systemd/system/netbird-overlay.service`: + + ```ini + [Unit] + Description=Setup tmpfs overlay for NetBird + After=local-fs.target tmp.mount + Before=netbird@netbird.service + + [Service] + Type=oneshot + ExecStart=/usr/local/bin/setup-netbird-overlay.sh + ExecStop=/bin/sh -c 'cp -a /tmp/netbird-state/. /root/netbird-state/' + RemainAfterExit=yes + + [Install] + WantedBy=multi-user.target + ``` + +5. Enable the overlay service: + + ```console + [root@pikvm ~]# systemctl daemon-reload + [root@pikvm ~]# systemctl enable netbird-overlay.service + ``` + +----- + +## Installing NetBird + +NetBird is installed from the [AUR](https://aur.archlinux.org/packages/netbird-bin) +using `makepkg`. The `netbird-bin` package provides pre-built binaries with SHA256 +checksum verification, avoiding the need to compile from source on the Pi. + +!!! note + `makepkg` must not run as root. PiKVM provides the unprivileged `kvmd-webterm` + user for this purpose. + +1. Update the system and install the build dependencies, then clone the AUR package: + + ```console + [root@pikvm ~]# pacman -Syu --needed git base-devel + [root@pikvm ~]# cd /tmp + [root@pikvm tmp]# git clone https://aur.archlinux.org/netbird-bin.git + [root@pikvm tmp]# chown -R kvmd-webterm:kvmd-webterm netbird-bin + ``` + +2. Build the package as the `kvmd-webterm` user: + + ```console + [root@pikvm tmp]# su -s /bin/bash kvmd-webterm -c 'cd /tmp/netbird-bin && makepkg' + ``` + + This will download the NetBird binary for your architecture, verify its + SHA256 checksum, and create a pacman package. + +3. Install the built package: + + ```console + [root@pikvm tmp]# pacman -U /tmp/netbird-bin/netbird-bin-*.pkg.tar.* + ``` + +4. Clean up the build directory: + + ```console + [root@pikvm tmp]# rm -rf /tmp/netbird-bin + [root@pikvm tmp]# cd ~ + ``` + +5. Create a systemd override to adapt the service for PiKVM's read-only filesystem: + + ```console + [root@pikvm ~]# mkdir -p /etc/systemd/system/netbird@.service.d + ``` + + Save the following as `/etc/systemd/system/netbird@.service.d/pikvm.conf`: + + ```ini + [Unit] + After=netbird-overlay.service + Requires=netbird-overlay.service + + [Service] + ExecStart= + ExecStart=/usr/bin/netbird service run --log-file syslog --daemon-addr unix:///var/run/netbird/%i.sock + LogsDirectory= + Environment=NB_DISABLE_SSH_CONFIG=true + ``` + + The key changes from the default service file are: + + * **`After=` and `Requires=`** include `netbird-overlay.service` so the + overlay is mounted before NetBird starts. + * **`ExecStart=`** is cleared then set with `--log-file syslog` instead of + a file path, since `/var/log` is read-only. + * **`LogsDirectory=`** is cleared to prevent systemd from trying to create + a log directory on the read-only filesystem. + * **`NB_DISABLE_SSH_CONFIG=true`** prevents NetBird from writing SSH + shortcut configuration to `/etc/ssh/ssh_config.d/99-netbird.conf`, + which would fail on the read-only filesystem. This only disables + the convenience of `ssh ` -- SSH over NetBird still works + using the peer's IP address directly. + + !!! note + The empty `ExecStart=` line is **not a typo**. In systemd, `ExecStart` + is a list-type setting. An empty assignment clears the previous value so + the next line replaces it rather than appending to it. + +6. Enable and start the services: + + ```console + [root@pikvm ~]# systemctl daemon-reload + [root@pikvm ~]# systemctl enable netbird@netbird.service + [root@pikvm ~]# systemctl start netbird-overlay.service + [root@pikvm ~]# systemctl start netbird@netbird.service + ``` + +----- + +## Updating NetBird + +Since NetBird is installed from the AUR rather than an official repository, +updates must be performed manually by rebuilding the package. + +```console +[root@pikvm ~]# rw +[root@pikvm ~]# cd /tmp +[root@pikvm tmp]# git clone https://aur.archlinux.org/netbird-bin.git +[root@pikvm tmp]# chown -R kvmd-webterm:kvmd-webterm netbird-bin +[root@pikvm tmp]# su -s /bin/bash kvmd-webterm -c 'cd /tmp/netbird-bin && makepkg' +[root@pikvm tmp]# pacman -U /tmp/netbird-bin/netbird-bin-*.pkg.tar.* +[root@pikvm tmp]# rm -rf /tmp/netbird-bin +[root@pikvm tmp]# cd ~ +[root@pikvm ~]# systemctl restart netbird@netbird +[root@pikvm ~]# ro +``` + +----- + +## Registering the device + +There are two ways to register your PiKVM with NetBird. The `--disable-dns` +flag is used in both cases to prevent NetBird from trying to write to +`/etc/resolv.conf` on the read-only filesystem. + +### Option 1: Setup key (recommended) + +Setup keys allow registration without any browser interaction, making them +ideal for headless devices like PiKVM. + +1. Log in to the [NetBird dashboard](https://app.netbird.io/) and navigate to + **Setup Keys**. Create a new key. + +2. Register your PiKVM using the setup key: + + ```console + [root@pikvm ~]# netbird up --setup-key --disable-dns + ``` + +### Option 2: Interactive SSO login + +You can also use the standard SSO login flow. PiKVM does not have a browser, +but the activation URL can be opened on any other device. + +1. Start the login flow: + + ```console + [root@pikvm ~]# netbird up --disable-dns + ``` + +2. NetBird will print an activation URL in the terminal, for example: + + ``` + Please do the SSO login in your browser. + If your browser didn't open automatically, use this URL to log in: + + https://login.netbird.io/activate?user_code=XXXX-XXXX + ``` + +3. Copy this URL and open it in a browser on your computer or phone. + Complete the login there. The PiKVM terminal will proceed automatically + once authentication is confirmed. + +### Verifying and persisting + +1. Verify the connection: + + ```console + [root@pikvm ~]# netbird status + ``` + + You should see `Status: Connected` and a NetBird IP address (e.g. `100.x.x.x`). + +2. Persist the authentication state so it survives reboots: + + ```console + [root@pikvm ~]# rw + [root@pikvm ~]# cp -a /tmp/netbird-state/. /root/netbird-state/ + [root@pikvm ~]# ro + ``` + +3. Reboot to verify everything starts automatically: + + ```console + [root@pikvm ~]# reboot + ``` + +!!! warning "Persist state after configuration changes" + Because the overlay uses tmpfs, any changes NetBird writes at runtime + (authentication tokens, key rotations, etc.) exist only in RAM. After making + configuration changes or re-authenticating, always persist the state: + + ```console + [root@pikvm ~]# rw + [root@pikvm ~]# cp -a /tmp/netbird-state/. /root/netbird-state/ + [root@pikvm ~]# ro + ``` + +----- + +## Configuring a client device + +* [Download](https://www.netbird.io/download) and install the NetBird client + on the system you are using (not the system you want to control). +* Check the [NetBird dashboard](https://app.netbird.io/) to see your connected peers. +* Open `https://` in your browser to access the PiKVM web interface. + +----- + +## Troubleshooting + +* **Service fails with `status=209/STDOUT`**: The service is trying to write + logs to a file on the read-only filesystem. Make sure the systemd override + includes `--log-file syslog` as described above. + +* **`mount: tmpfs: mount failed`**: The tmpfs mount in the overlay script is + failing. Check that `/tmp` is writable and that the script is executable + (`chmod +x /usr/local/bin/setup-netbird-overlay.sh`). + +* **DNS lookup failures (`DeadlineExceeded`)**: If NetBird cannot reach + `api.netbird.io`, check that your PiKVM has working DNS resolution: + + ```console + [root@pikvm ~]# curl -v --max-time 10 https://api.netbird.io:443 + ``` + + If DNS is broken, verify `/etc/resolv.conf` contains a valid nameserver. + A stale NetBird daemon process can also cause this; restart the service: + + ```console + [root@pikvm ~]# systemctl restart netbird@netbird + ``` + +* **Need to re-authenticate after reboot**: You forgot to persist the state. + Run `netbird up --setup-key --disable-dns` again, then persist: + + ```console + [root@pikvm ~]# rw + [root@pikvm ~]# cp -a /tmp/netbird-state/. /root/netbird-state/ + [root@pikvm ~]# ro + ``` + +* If something does not work, the usual advice is to completely remove NetBird + and perform a clean installation: + + ```console + [root@pikvm ~]# rw + [root@pikvm ~]# netbird down + [root@pikvm ~]# systemctl stop netbird@netbird + [root@pikvm ~]# systemctl disable netbird@netbird netbird-overlay + [root@pikvm ~]# pacman -Rns netbird-bin + [root@pikvm ~]# rm -rf /var/lib/netbird /root/netbird-state + [root@pikvm ~]# rm -rf /etc/systemd/system/netbird@.service.d + [root@pikvm ~]# reboot + ``` + + Now follow the instructions from the beginning to re-install. diff --git a/mkdocs.yml b/mkdocs.yml index da9dec1d..94a5b4c4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -125,6 +125,7 @@ nav: - "Reverse proxy": reverse_proxy.md - "Tailscale VPN": tailscale.md - "Cloudflare tunnel": cloudflared.md + - "NetBird VPN": netbird.md - "Setting up Wi-Fi": wifi.md - "Setting up 3G/4G/LTE modem": modem.md - "Let's Encrypt certificates": letsencrypt.md