Self-Hosting Netbird using Hetzner

If you're trying to self-host a Netbird deployment, you probably already know why you want to do that. If you're not sure, it allows you to form a virtual private network of your devices over the internet: i.e., easily and securely access your own devices as long as they're connected to the internet. I used Hetzner to host the Netbird deployment, but you can use your own hardware or any other cloud provider to do the same.

This is mostly a reproduction of Netbird's self-hosted quickstart guide. By the time this is done, you'll have

Outline

  1. Create a Hetzner project just for this.
  2. Create a firewall configuration with the appropriate ports.
  3. Create a VPS with a public IPv4 address.
  4. Point your desired domain at your VPS.
  5. Install the Netbird prerequisites
  6. Install the Netbird deployment
  7. Initial sign-in and admin account
  8. Non-admin user for interactive authentication
  9. Setup keys for non-interactive athentication
  10. Netbird agent as a Docker sidecar
  11. Netbird agent on Debian
  12. Netbird agent on macOS
  13. Netbird agent on iOS

1. Create Hetzner Project

This is completely optional, but it can be a nice way to segregate this fundamental piece of infrastructure from whatever else you're doing.

2. Create a Firewall Configuration

Whether or not you have this in an isolated project, you can create a named firewall configuration just for the Netbird server. The reason to do this before creating the VPS is that it's one click to add it to your new VPS after.

The required ports for the deployment is listed here: https://docs.netbird.io/selfhosted/selfhosted-quickstart#requirements

Protocol Port Reason
TCP 80 HTTP (Let's Encrypt)
TCP 443 HTTPS (Dashboard & API)
TCP 33073 NetBird Management
TCP 10000 NetBird Signal
TCP 33080 Zitadel
UDP 3478 STUN
UDP 49152-65535 TURN relay

3. Create an Appropriate VPS

Even the leanest VPS is enough to run the control server, so we'll only be considering the cheapest configurations. Choose a region close to your primary location. Netbird will use this VPS for

In the region closest to me (us-west), Hetzner only offers x86 instances. These are a bit more expensive than Hetzner's Arm instances, but they're 100ms closer than the closest Arm instances in Helsinki.

I created the VPS with Debian 12 because

Hetzner attaches a public IPv4 address to each server by default (for an additional fee). Note this IP address for the DNS configuration.

I attached the firewall rules defined above when I created the VPS.

You can either provide an SSH key, or omit this and have Hetzner email you a password. If you opt for a password, you will have to set a new one the first time you ssh in. If you choose a password, you can always add an SSH key later.

4. DNS configuration

Netbird's installation script expects to be able to provision a TLS certificate, so it will need a valid domain name aimed at itself before you run it. I added an "A" record to my DNS. I will use netbird.example.com as a placeholder for this post.

| Type | Host | Answer | |-|-|-|-| | A | netbird.example.com | |

5. Install Software Prerequisites

https://docs.netbird.io/selfhosted/selfhosted-quickstart#requirements

Connect to your VPS via ssh

ssh root@netbird.example.com

update its software, and install curl and jq:

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y curl jq

Then install Docker. Check the website for up-to-date instructions

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Then, do the post-installation step

sudo usermod -aG docker $USER

Exit and ssh in again

6. Install the Netbird Stack

I used the one-shot "easy install" script Netbird provides:

export NETBIRD_DOMAIN=netbird.example.com; curl -fsSL https://github.com/netbirdio/netbird/releases/latest/download/getting-started-with-zitadel.sh | bash

It will take a minute or two to fire up and configures several Docker containers running the various components of the deployment.

netbirdio/relay:latest
netbirdio/dashboard:latest
netbirdio/signal:latest
coturn/coturn
netbirdio/management:latest
ghcr.io/zitadel/zitadel:v2.64.1
postgres:16-alpine
caddy

If all goes well you will see a message like this in the terminal:

You can access the NetBird dashboard at https://netbird.example.com
Login with the following credentials:
Username: admin@netbird.example.com
Password: <some super long password here>

7. Initial Sign-in and Create New Admin Password

Open up your favorite browser and navigate to https://netbird.example.com

Put in the Username and Password provided above.

You will immediately be asked to set a new password.

8. Add a non-admin User for Interactive Authentication

Now we'll add another use to authenticate interactive client devices (e.g. phone, laptop) to the network.

Navigate to https://netbird.example.com/ui/console/users. I can't figure out how to get there by clicking around from https://netbird.example.com, so I just navigate to that URL directly.

  1. Fill in the required information.
  2. Check "email verified." The Netbird configuration described thus far doesn't have SMTP set up, so it won't be able to send a verification email.
  3. Check "set initial password."

The first time the user logs in, they will have to choose a new password of their own.

9. Add some Setup Keys for Non-Interative Authentication

A setup key can be provided to the Netbird agent to allow agents to be added non-interactively to your network. These must be kept secret, as anyone who has them and the address of your control server will be able to connect to your network.

Navigate to https://netbird.example.com/setup-keys.

When you create a key you will be asked the following

The devices added under each key can be viewed separately in the Netbird UI, so I create one key for Docker containers (see below) and one setup key for actual hardware servers. They both are reusable with no limits and no expiration.

10. Using Netbird as a Sidecar Docker Container

This is a convenient way to connect a specific Docker container to the network.

Here is an example lifted from this netbirdio Github issue using nginx as an example.

In this example, the traffic for Nginx all goes through Netbird. You can also optionally make the container available without Netbird by exposing ports. The Netbird agent needs a persistent volume or filesystem mount to store some of its state if you want it to keep the same domain name and/or IP address.

version: '3.8'
services:
  nginx:
    image: nginx:alpine # just an example of a container you want to access via your Netbird network
    volumes:
      - ./content:/usr/share/nginx/html:ro
#    ports: 
#      - 80:80 # needed for access without netbird
#  network_mode: "service:netbird" # or you can put the equivalent on the other service
  netbird:
    image: netbirdio/netbird:latest
    volumes:
      - ./client:/etc/netbird 
    cap_add:
      - NET_ADMIN
      - SYS_ADMIN
      - SYS_RESOURCE
    environment:
      NB_SETUP_KEY: <SETUP_KEY>
      NB_HOSTNAME: <hostname>
      NB_MANAGEMENT_URL: https://netbird.example.com # change to your domain
    # link NetBird network to Nginx
    network_mode: "service:nginx" # or you can put the equivalent on the other service

You can use the ports field on your server image to also make it available without Netbird.

Your sidecar Netbird container should mount a volume into /etc/netbird. This allows netbird to save some state if the container restarts, preserving the IP address and domain name. You will need to provide a setup key <SETUP_KEY> to connect and a hostname <hostname> to control how your service will appear on your network (as <hostname>.netbird.selfhosted).

11. Using Netbird on Debian

Check Netbird docs for up-to-date instructions:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg -y
curl -sSL https://pkgs.netbird.io/debian/public.key | sudo gpg --dearmor --output /usr/share/keyrings/netbird-archive-keyring.gpg
echo 'deb [signed-by=/usr/share/keyrings/netbird-archive-keyring.gpg] https://pkgs.netbird.io/debian stable main' | sudo tee /etc/apt/sources.list.d/netbird.list

Then, start the agent and provide one of your setup keys:

sudo apt-get install netbird
sudo netbird up --management-url https://netbird.carlpearson.net --setup-key <SETUP KEY> 

12. Using Netbird on macOS

Netbird provides an installation package. When you start the app, it will drop a little icon in the taskbar.

One aditional wrinkle is that "Quit" does not disconnect you. You have to click "Disconnect" first.

13. Using Netbird on iOS

There is a Netbird iOS app on the Apple App Store.