WireGuard Mesh Networking: Building a Zero-Trust Network Between Servers and Your NAS with Tailscale and Netmaker

A hands-on guide to building a Zero-Trust mesh network between remote servers and a NAS with WireGuard, covering two concrete paths: Tailscale (SaaS) and Netmaker (self-hosted).

WireGuard Mesh Networking: Building a Zero-Trust Network Between Servers and Your NAS with Tailscale and Netmaker

Connecting two servers with a point-to-point WireGuard VPN takes just a few minutes. The trouble starts when the number of nodes grows to five, ten, twenty: cloud servers scattered across different providers, a NAS on-site, a few Raspberry Pis, and the team's laptops. Manually configuring every single peer pair quickly turns into a nightmare of public keys, IP addresses, and configuration files that need updating by hand with every change.

This is where mesh networking comes in: a network where every device can talk directly to every other authorized device without going through a single central point, and where access doesn't depend on "being inside the company perimeter" but on explicit rules checked for every connection. This second principle has a name: Zero Trust. In this guide we'll see how to actually build a Zero-Trust mesh between remote servers and a NAS, using WireGuard as the cryptographic foundation and two tools that orchestrate it in very different ways: Tailscale (a SaaS service) and Netmaker (self-hosted).

WireGuard in a nutshell: why it became the standard

WireGuard is a modern VPN protocol designed to be easy to audit (its source code is orders of magnitude smaller than OpenVPN or IPsec) and fast, since it has run directly inside the Linux kernel since version 5.6. It uses modern cryptography such as Curve25519 for key exchange and ChaCha20 for traffic encryption, and identifies each device through a public/private key pair rather than usernames and passwords.

The limitation of "plain" WireGuard isn't security, it's organization: by default it's built for point-to-point links. Building a mesh with many nodes means manually generating and distributing every peer's keys to every other peer, updating AllowedIPs addresses with every change, and tracking it all by hand. That's exactly the kind of work Tailscale and Netmaker automate: both use the WireGuard protocol under the hood, but add a layer of automatic orchestration (key distribution, peer discovery, access rules) that makes it manageable even with dozens of nodes.

The Zero Trust principle applied to networking

The traditional network security model is based on a perimeter: if a device is "inside" (in the office, on the corporate VPN), it's trusted almost completely. The problem is that once a perimeter is breached - a stolen credential, a compromised laptop - an attacker has free rein to move laterally across systems.

Zero Trust flips that approach: no device or user is automatically trusted, not even ones already "inside" the network. Every connection is authenticated and authorized individually, following the principle of least privilege: a backup server should only be able to reach the NAS it writes to, not the production database or the administrator's workstation. Applied to a WireGuard mesh, this translates into two concrete things: strong identity for every node (the WireGuard public key, unique per device) and a rule system (an ACL, or access control list) that explicitly decides who can talk to whom, instead of letting "anyone on the network" reach everything.

Tailscale and Netmaker: two different philosophies

Both Tailscale and Netmaker build an automated WireGuard mesh, but they start from opposite premises. Tailscale is a SaaS service: the control plane (authentication, key distribution, management interface) is run by Tailscale's own servers, while traffic between devices travels directly peer-to-peer whenever possible. Netmaker, on the other hand, is built to be self-hosted: you install the control plane (the free, open-source Community Edition) on your own server and remain the owner of the entire infrastructure, data included.

This difference shows up in pricing too. Tailscale has a free "Personal" plan for non-commercial use, covering up to 6 users with unlimited devices; team plans start at $8 per user per month (the Standard plan), up to $18 for the Premium plan aimed at larger organizations. Netmaker instead offers a free, open-source Community Edition with no stated limits on devices or networks, plus paid Team and Business plans billed per active connection, starting at roughly $2 per connection per month, aimed at those who want extra features like automatic failover or advanced user management.

In practical terms: if you want to get started right away without running an extra server, and you're comfortable handing the control plane to an outside provider, Tailscale is the quicker route. If keeping the entire infrastructure - including the server that decides "who can talk to whom" - under your own control is the priority, Netmaker is worth considering, at the cost of having one more server to manage.

Route one: a Zero-Trust mesh with Tailscale

Tailscale installs on every device that needs to join the network (servers, laptops, Raspberry Pis) through a lightweight client. Once authenticated, devices get a stable virtual IP address in the private 100.64.0.0/10 range (the same range used for CGNAT) and can reach each other directly.

Exposing a NAS without installing anything on it

Many NAS devices don't support installing a Tailscale client directly, or you'd rather avoid touching the vendor's own system. The answer is the subnet router pattern: install Tailscale on an always-on device on the same local network as the NAS (a small Linux box or a Raspberry Pi, say), and let it act as a "bridge" that exposes the entire subnet to the mesh, with the NAS itself needing to know nothing about WireGuard or Tailscale.

On the bridge device, after enabling IP forwarding at the system level, start the client with:

tailscale up --advertise-routes=192.168.1.0/24

where 192.168.1.0/24 is the local subnet the NAS sits on. That step alone isn't enough: the advertised route has to be approved by an admin in the web admin console ("Machines" section, the device tagged with the "Subnets" badge), unless it's already covered by an autoApprovers rule in the policy file. Only then can other mesh nodes - if set to accept routes with tailscale set --accept-routes (the default behavior on macOS, iOS, Android, and Windows) - reach the NAS at its original local IP address, as if they were on the same LAN.

Writing the access rules (ACLs/grants)

By default, a brand-new "tailnet" (Tailscale's name for its private network) lets every device reach every other device: everything is allowed except for explicit rules. To actually enforce Zero Trust, you need to flip that logic around: remove the default allow-all rule and write only the permissions you actually need in the JSON policy file. The modern syntax is called grants (preferred over the older acls format, though the two can coexist), and each rule specifies a source, a destination, and the allowed ports:

{
  "hosts": {
    "backup-server": "100.64.0.10",
    "nas": "100.64.0.20"
  },
  "grants": [
    {
      "src": ["backup-server"],
      "dst": ["nas"],
      "ip": ["tcp:445", "tcp:22"]
    }
  ]
}

In this example, only the backup server can reach the NAS, and only on the SMB (445) and SSH (22) ports: no other device on the mesh - not even one with full access to other systems - can touch it. To organize permissions across multiple devices, you can use tags, assigned in the policy's tagOwners section: a tag moves a device's "ownership" from a single human account to the tag itself, so access no longer depends on who originally logged into that machine. One non-trivial practical detail worth noting: removing a tag from a device isn't simple - it often requires removing the node from the network and re-registering it from scratch - so it's worth planning your tagging scheme carefully before putting it into production.

SSH access without keys to manage

One practical benefit of relying on Tailscale's identity for the whole network is being able to enable "keyless" SSH access: turning it on for a server with tailscale set --ssh makes SSH authentication rely on the tailnet identity instead of keys that need to be generated, distributed, and revoked by hand. Rules about who can SSH in, and as which system user, live in a separate block of the policy:

{
  "ssh": [
    {
      "action": "check",
      "src": ["group:sysadmin"],
      "dst": ["tag:server"],
      "users": ["deploy"]
    }
  ]
}

With "action": "check", access requires periodic re-authentication (the interval is set with checkPeriod), useful on the more sensitive servers; with "action": "accept", access is granted immediately once identity is verified. Either way, the operating system's own SSH configuration still needs to allow that specific user.

Two practical warnings before going to production: node keys expire after 180 days by default, which can silently disconnect a subnet router or exit node unless you disable expiry on devices acting as permanent infrastructure; and policy changes take effect immediately on save, so an overly restrictive rule can cut off the very SSH session you're working in - always review the diff before confirming changes.

Route two: a self-hosted mesh with Netmaker

If keeping full control of the infrastructure is the priority, Netmaker Community Edition lets you install your own control plane on a server, without relying on an outside provider to decide who can access what.

Requirements and installation

For the Community Edition, Netmaker requires an Ubuntu 24.04 server (a VM, bare metal, or even the same machine running your other services), with a minimum of 1 GB RAM, 1 CPU, and 2 GB of storage for testing, but at least 2 GB RAM and 2 CPUs for production use. You'll need a static public IP address and, ideally, a domain name with DNS management access, because the dashboard, API, MQTT broker, and monitoring tools (Prometheus, Grafana) each need their own public subdomain (or a wildcard such as *.netmaker.example.com). You'll also need to open ports 80/TCP and 443/TCP for certificates and the web UI, plus 51821/UDP for the agent's WireGuard traffic.

The Community Edition's guided install boils down to downloading and running the official script from Netmaker's GitHub repository:

curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh -o /root/nm-quick.sh
chmod +x /root/nm-quick.sh
sudo /root/nm-quick.sh

The script automatically sets up TLS certificates (via Caddy), the MQTT broker used for client communication, and the admin dashboard. A useful heads-up for anyone using Cloudflare as a DNS proxy: disable proxying (the "grey cloud" instead of orange) on the records used by Netmaker, otherwise MQTT traffic gets blocked in a way Netmaker itself can't diagnose.

Creating the network and adding nodes

On first login to the dashboard you create an admin account, then create a new network, choosing a private address range that doesn't overlap with any other network already in use (for networks under 254 machines, a block like 10.11.12.0/24 is more than enough). The Netmaker server automatically joins the network as its first node.

To add a remote server or the bridge device toward the NAS, generate an enrollment key from the dashboard ("Keys" section), setting how many times it can be used and which networks it grants access to. On the new host, after confirming WireGuard and systemd are installed, install the netclient for your operating system and register the node with:

netclient register -k  -s grpc.mydomain.com -p 50051

Moments later the node appears in the admin dashboard, and you can verify connectivity with a simple ping to its private mesh address from another node already connected. For nodes added later to a network you're already part of, you can use a dedicated registration token instead of an enrollment key, purpose-built for that case.

Netmaker handles mesh security through network-level ACLs (which nodes within the same virtual network are allowed to talk to each other) and tags that can be assigned to enrollment keys - a different mechanism, but conceptually similar to Tailscale's grants: here too, the goal is to prevent "being part of the mesh" from automatically meaning "having access to everything".

Security best practices, whichever tool you choose

Regardless of which route you take, a few precautions apply to both. First: disable automatic key expiry on devices that play a permanent infrastructure role, such as the subnet router exposing the NAS or the Netmaker server itself - an unexpectedly expired key on a critical node means a silent outage. Second: always apply the principle of least privilege when writing access rules, granting each node only the ports and peers it actually needs, not "everything it needs plus a bit extra just in case" - that's exactly the opposite of the Zero Trust spirit. Third: keep both the underlying WireGuard client and the orchestration software (Tailscale or Netmaker's netclient) updated, since both receive security fixes periodically. Fourth, and often overlooked: test access rules before relying on them in production, checking not only that authorized connections work, but also that unauthorized ones are actually blocked.

Which one should you choose?

There's no universal answer, but here's some practical guidance. For a homelab, a small team, or anyone who wants to get started right away without running an extra server, Tailscale offers the fastest path, a generous free plan for personal use, and policy management granular enough to implement a genuine Zero Trust model. For those already running their own server infrastructure, facing compliance requirements that demand keeping data and the control plane on-premises, or simply preferring not to depend on an outside SaaS provider for something as critical as network access, Netmaker Community Edition offers the same WireGuard-based security guarantees, at the cost of one more server to administer and keep updated. Either way, the end result is the same: an encrypted mesh, fast because it's built on WireGuard, and designed around the principle that no connection is granted by default - only because it was explicitly authorized.

Official sources

Share

What's Your Reaction?

Like Like 0
Dislike Dislike 0
Love Love 0
Funny Funny 0
Angry Angry 0
Sad Sad 0
Wow Wow 0