Self-Host NetBird: A Mesh VPN That Feels Like Tailscale, But Yours
Self-host NetBird for private homelab access without port forwarding. A practical Docker guide with setup, ACLs, routing, and real gotchas.
I love Tailscale. I also get twitchy when the thing that unlocks my whole homelab depends on somebody else’s control plane.
That is the annoying self-hoster brain disease: you find a tool that works, then immediately ask, “Can I run this myself and make my weekend worse?”
NetBird is the answer I would try before building another hand-rolled WireGuard spiderweb. It gives you a mesh VPN with device enrollment, groups, access rules, DNS, and routes. The difference is that you can self-host the management server instead of trusting a SaaS dashboard with the keys to your private kingdom.
This is not the smallest setup in the world. If you only have one VPS and one laptop, plain WireGuard is still cleaner. But if you have a homelab, a VPS, a NAS that cannot run an agent, and a couple of laptops that come and go, NetBird hits a very nice middle ground.
The short version
NetBird is a WireGuard-based overlay network.
Each device gets a private NetBird IP. Devices talk directly when they can, fall back to relays when they cannot, and receive policy from your self-hosted management server.
I would use NetBird when you want:
- Tailscale-style onboarding without using Tailscale
- Access control lists that normal humans can read
- Private access to dashboards like Portainer, Uptime Kuma, Grafana, and Home Assistant
- Subnet routing for devices that cannot run the client
- A real admin UI instead of a folder full of WireGuard configs named
laptop-final2.conf
I would not use it if you need the absolute simplest VPN possible. For that, use WireGuard directly or read our WireGuard self-hosting guide.
NetBird vs Tailscale vs Headscale
Let’s get the awkward comparison out of the way.
| Option | Best for | Main trade-off |
|---|---|---|
| Tailscale | Fastest setup, polished clients, least maintenance | SaaS control plane unless you switch to Headscale |
| Headscale | Self-hosted Tailscale control server | No official web UI, more DIY edges |
| NetBird | Self-hosted mesh VPN with admin UI and ACLs | More moving parts than plain WireGuard |
| Plain WireGuard | Tiny, fast, boring in the best way | Manual keys and routes get old quickly |
My take: NetBird is the one I would hand to a friend who wants self-hosted remote access but does not want to become a WireGuard librarian.
Headscale is great if you already like the Tailscale ecosystem. NetBird feels more like a complete self-hosted product. That matters when you revisit the setup six months later and have forgotten every clever decision you made.
What you need before installing
You need a small public server. A cheap VPS is fine.
For a personal setup, I would start with:
- 1 vCPU
- 1 GB RAM minimum, 2 GB nicer
- Debian or Ubuntu
- A domain like
netbird.example.com - Docker and Docker Compose
- Ports 80 and 443 open for the web UI and HTTPS
- UDP 3478 open for STUN/TURN-style connectivity help
You also need a real DNS record pointing at the VPS.
Do not put this behind three layers of mystery proxy on day one. Get the basic setup working first, then get fancy.
Step 1: prepare the server
Update the VPS and install Docker if you have not already:
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
Log out and back in so your user can run Docker.
Then create a directory for NetBird:
sudo mkdir -p /opt/netbird
sudo chown -R $USER:$USER /opt/netbird
cd /opt/netbird
I like /opt for this kind of infrastructure service. It keeps the stack away from random home-directory experiments, which is where good intentions go to die.
Step 2: use NetBird’s self-hosted installer
NetBird publishes a self-hosting installer that generates the Compose files and configuration for you.
Run it from the server:
curl -fsSL https://pkgs.netbird.io/install.sh | sh
Then follow the self-hosting flow from the official docs. You will be asked for your domain, email, and identity provider settings.
Official docs live here: NetBird self-hosting guide.
I am intentionally not pasting a giant static Compose file here because these stacks change. Hard-coding old config into a blog post is how people end up debugging yesterday’s YAML with today’s containers.
The shape of the stack is usually:
- Management service
- Dashboard
- Signal service
- Relay service
- Coturn or relay helper
- Identity provider integration
- Reverse proxy / TLS layer
After generation, start it:
docker compose up -d
Check logs immediately:
docker compose ps
docker compose logs -f --tail=100
If anything is red, fix it now. Do not continue with a half-working control plane. VPN problems become very weird when the foundation is already cracked.
Step 3: log in and create your first setup key
Open your dashboard:
https://netbird.example.com
Sign in with the identity provider you configured.
Then create a setup key. This is the token your clients use to join the network.
My usual pattern:
- One reusable setup key for servers
- One expiring setup key for laptops
- No permanent setup key for random test machines
If you are testing, give the key a short expiration. You can always make another one. You cannot un-leak a token from a terminal screenshot you pasted into Discord because you were “just helping someone quickly.”
Step 4: install the NetBird client
On a Linux machine you want to join:
curl -fsSL https://pkgs.netbird.io/install.sh | sh
sudo netbird up --setup-key YOUR_SETUP_KEY
Then check status:
netbird status
You should see a NetBird IP and your peer list.
For desktops and phones, use the official clients from the NetBird downloads page. The mobile clients are the difference between “I can fix this from a coffee shop” and “I guess my dashboard is dead until I get home.”
Step 5: lock services to the private network
This is the part people skip, and it is the part that actually matters.
A VPN is not magic if your services are still exposed on the public internet.
For a Docker app, bind ports to localhost or to your private interface where possible. For example, a local-only Uptime Kuma might look like this:
services:
uptime-kuma:
image: louislam/uptime-kuma:1
restart: unless-stopped
volumes:
- ./data:/app/data
ports:
- "127.0.0.1:3001:3001"
Then put your reverse proxy on the NetBird network path, or access the service over an SSH tunnel from a NetBird-connected machine.
If the app must listen on the server’s normal interface, use a firewall. A simple UFW pattern is:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3478/udp
sudo ufw enable
For app ports, only allow what you actually need. The goal is boring logs. Boring logs are beautiful.
🚀NordVPN
Secure your server with a reliable VPN.
Affiliate link — we may earn a commission at no extra cost to you.
Step 6: use groups and access rules early
Do not wait until you have 19 peers to design access rules.
Start with simple groups:
adminsserverslaptopsphonesguests
Then make rules that match how you actually work.
Example policy ideas:
| Source | Destination | Why |
|---|---|---|
| admins | servers | Full management access |
| phones | home-assistant | Quick smart-home access |
| laptops | dashboards | Daily admin work |
| guests | one demo service | Never your whole network |
The strong opinion: default-open private networks become messy fast. People think “it’s only my tailnet” and then add a work laptop, a travel phone, an old tablet, and a test VM they forget about.
Use groups now. Future you will be less grumpy.
Step 7: add a subnet route for dumb devices
Some devices cannot run NetBird.
My favorite examples are NAS boxes, IP cameras, printers, and random IoT hubs with firmware that looks like it was built during a thunderstorm.
For those, install NetBird on a Linux machine inside that LAN and advertise the subnet route from there. The exact command can vary by client version and policy setup, so check NetBird’s routing docs before copy-pasting commands into production.
The pattern is:
- Pick a stable Linux box on the LAN.
- Enable IP forwarding.
- Advertise the LAN subnet in NetBird.
- Approve the route in the admin UI.
- Restrict who can use that route.
On Debian or Ubuntu, IP forwarding usually starts like this:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-netbird-routing.conf
sudo sysctl -p /etc/sysctl.d/99-netbird-routing.conf
Be careful with subnet routes. They are incredibly useful and incredibly easy to over-share.
A route to 192.168.1.0/24 might include your NAS, but it might also include a printer admin panel with the password admin. Ask me how I know. Actually, don’t.
Step 8: back up the control plane
If you self-host the control plane, you own the recovery plan.
Back up:
- The Docker Compose directory
- Environment files
- Volumes
- Identity provider configuration
- Any database used by the stack
I would put this into the same backup workflow as the rest of your infrastructure. If you need a model, read our VPS backup strategy and adapt it.
Test the restore. Not “I looked at the backup folder and felt safe.” Actually restore it on a throwaway VPS and log in.
The first time I tested a VPN control-plane restore, I discovered I had backed up the config but not the volume with the important state. That was a humbling little clown show.
Common gotchas
DNS is usually the villain
If clients enroll but cannot reach the dashboard reliably, check DNS first.
Make sure your NetBird domain resolves to the right public IP. If you use Cloudflare, start with DNS-only mode while testing unless the docs for your exact setup say otherwise.
UDP matters
Mesh VPNs like direct paths. Direct paths often need UDP.
If everything works but feels slow, your peers may be relaying instead of connecting directly. Check firewalls on the VPS, your home router, and any cloud security group.
Identity provider setup is not optional homework
The login layer matters because it controls who can enroll and manage peers.
Use strong passwords, MFA, and a provider you understand. If your identity provider is a mess, your VPN is a mess with better branding.
Do not expose admin dashboards twice
I have seen people set up NetBird, then leave Grafana publicly exposed because “it already had a password.”
No. Pick one path. If a dashboard is private, make it private.
My recommended starter layout
For a small homelab, I would do this:
- NetBird control plane on a cheap VPS
- One admin laptop
- One phone
- One home server
- One VPS running public apps
- One subnet route from the home server to the LAN
- ACLs that only let admin devices reach server ports
Then I would move private dashboards off the public internet one by one:
- Portainer
- Uptime Kuma
- Grafana
- Home Assistant
- Proxmox
- NAS admin UI
Do not migrate everything in one dramatic Saturday session. That is how you lock yourself out and learn humility through serial console access.
Should you self-host NetBird?
Yes, if remote access is becoming a real part of your setup.
No, if you are trying to avoid maintenance entirely. Self-hosting the thing that grants access to your other self-hosted things is powerful, but it is also a responsibility. Patch it. Back it up. Monitor it. Keep a break-glass SSH path that does not depend on the VPN being healthy.
My practical advice: try NetBird on two machines first. Laptop to VPS. Then add your home server. Then add routing and ACLs.
If it still feels good after a week, start pulling dashboards off the public internet. That is the win: fewer exposed ports, cleaner access, and a network that feels like yours again.
And if you decide NetBird is too much? No shame. Plain WireGuard is still excellent. Boring tools that work are the whole point of a sane homelab.
Stay in the loop 📬
Get self-hosting tutorials, tool reviews, and infrastructure tips delivered to your inbox. No spam, unsubscribe anytime.
Join 0 self-hosters. Free forever.