WireGuard Mesh & Tunnel Series
    Part 1 of 6

    WireGuard Foundations & Mesh Architecture Concepts

    The vocabulary the rest of the series builds on — protocol primitives, key management, mesh topologies, NAT traversal, and a hands-on three-node manual mesh.

    45 minutes
    2–3 RamNode VPS for the manual mesh
    Prerequisites

    Two RamNode VPS, basic Linux networking

    Time

    ~45 minutes

    Outcome

    Working three-node WireGuard mesh and the mental model for Parts 2–5

    Why Overlay Networks Earn Their Keep

    A VPS provider gives you a public IP and a firewall. That is enough to run public services. It is not enough to run private ones safely. The moment you have:

    • • Two VPS instances in different regions that need to replicate a database
    • • A home lab you want to reach without exposing SSH to the internet
    • • A staging environment that should only be reachable by your team
    • • Application servers that should only accept traffic from a known set of frontends
    • • A CI runner inside a private network that needs to reach a build artifact store

    you have an overlay network problem. The traditional answers (site-to-site IPSec, OpenVPN, port forwarding with HTTP basic auth) have a cost-of-operation problem at any meaningful scale. Overlay mesh networks emerged to make the easy case easy and the hard case possible.

    WireGuard in One Section

    WireGuard is a Layer 3 tunnel protocol built on a small set of modern cryptographic primitives: Curve25519 for key exchange, ChaCha20 for encryption, Poly1305 for authentication, BLAKE2s for hashing. It runs in the Linux kernel as of 5.6, in FreeBSD, OpenBSD, Windows, macOS, iOS, and Android. The userspace implementation (wireguard-go) exists for platforms without a kernel option.

    The protocol has no concept of users, sessions, or dynamic configuration. It has peers. Each peer is identified by a public key. To talk to a peer you need:

    1. Its public key
    2. Its endpoint (IP and port) if you intend to initiate the connection
    3. The list of source IPs you will accept from it (allowed IPs)

    That is the entire model. No CA, no enrollment protocol, no key rotation service. WireGuard moves packets between peers with strong cryptography and a tiny attack surface (about 4,000 lines of kernel code).

    /etc/wireguard/wg0.conf on server
    [Interface]
    PrivateKey = <server-private-key>
    Address = 10.10.0.1/24
    ListenPort = 51820
    
    [Peer]
    PublicKey = <client-public-key>
    AllowedIPs = 10.10.0.2/32

    Bring it up with wg-quick up wg0, persist with systemctl enable wg-quick@wg0. That is the foundation everything else in this series is built on or competes against.

    Generating Keys

    wg genkey | tee privatekey | wg pubkey > publickey

    Keep privatekey mode 0600, never share it, never put it in git. The public key is safe to distribute.

    What WireGuard Does Not Do

    It does not punch through NAT for you. It does not discover peers. It does not rotate keys. It does not enforce identity beyond key possession. It does not give you a dashboard, an API, or audit logs. Every higher-level tool in this series exists because someone needed one or more of those things.

    Mesh Topologies

    There are three useful topologies. Every tool in this series implements one or more of them.

    • Full mesh. Every node has a direct WireGuard tunnel to every other node. Latency is optimal (one network hop in the overlay). Failure of any single node only affects traffic to that node. The cost: N nodes need N*(N-1)/2 tunnels, and every node needs every other node's public key and endpoint. Scales poorly past 50 nodes by hand. Netbird and Netmaker handle the bookkeeping.
    • Hub and spoke. All nodes connect to a central hub. Traffic between spokes routes through the hub. The hub is a single point of failure and a bandwidth bottleneck. Simple to reason about, easy to enforce central policy, only one node needs a public endpoint. The topology of every reverse-tunnel tool in the series.
    • Relay-assisted mesh. Nodes attempt direct connections; when they fail (typically symmetric NAT on both sides) traffic relays through a public node. Netbird, Netmaker, and Nebula all implement this. The relay node sees encrypted traffic only, but it sees the metadata of who is talking to whom.

    The NAT Traversal Problem

    WireGuard is UDP. To establish a tunnel between two peers, at least one peer must be reachable at a known UDP endpoint. If both peers are behind NAT and neither has a port forward, the tunnel fails.

    • One peer has a public IP. Always works. This is why every mesh deployment in this series uses at least one VPS as an anchor.
    • STUN-style hole punching. Both peers send packets outward simultaneously. NAT mappings get created, and if NAT is friendly (full or restricted cone) the packets meet in the middle.
    • TURN-style relay. When hole punching fails, traffic relays through a known-reachable node.
    • Persistent keepalive. PersistentKeepalive = 25 sends a keepalive every 25 seconds, holding NAT mappings open that would otherwise drop after 30–60 seconds of inactivity.

    A Hands-On Three-Node Manual Mesh

    Before any management tool, build a mesh by hand. This gives you the mental model to debug everything that follows.

    Topology. Two RamNode VPS (nyc and lax) and one home machine (lab). Use 10.10.0.0/24 as the overlay.

    /etc/wireguard/wg0.conf on nyc (anchor)
    [Interface]
    PrivateKey = <nyc-priv>
    Address = 10.10.0.1/24
    ListenPort = 51820
    PostUp = sysctl -w net.ipv4.ip_forward=1
    PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
    PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
    
    [Peer] # lax
    PublicKey = <lax-pub>
    AllowedIPs = 10.10.0.2/32
    Endpoint = <lax-public-ip>:51820
    
    [Peer] # lab
    PublicKey = <lab-pub>
    AllowedIPs = 10.10.0.3/32
    PersistentKeepalive = 25
    lax
    [Interface]
    PrivateKey = <lax-priv>
    Address = 10.10.0.2/24
    ListenPort = 51820
    
    [Peer] # nyc
    PublicKey = <nyc-pub>
    AllowedIPs = 10.10.0.1/32
    Endpoint = <nyc-public-ip>:51820
    
    [Peer] # lab
    PublicKey = <lab-pub>
    AllowedIPs = 10.10.0.3/32
    PersistentKeepalive = 25
    lab (behind home NAT)
    [Interface]
    PrivateKey = <lab-priv>
    Address = 10.10.0.3/24
    
    [Peer] # nyc
    PublicKey = <nyc-pub>
    AllowedIPs = 10.10.0.0/24
    Endpoint = <nyc-public-ip>:51820
    PersistentKeepalive = 25

    Note the asymmetry. The home machine routes all 10.10.0.0/24 through nyc because it cannot reliably reach lax directly through NAT. This is hub-and-spoke with extra steps. Building a real full mesh through NAT requires either router port forwarding or a tool that does hole punching for you. That is the value proposition of every managed mesh tool in this series.

    Firewall and sysctl Baseline

    Whatever tool you deploy, the host needs the same baseline preparation.

    # Enable IP forwarding for any node that will route between interfaces
    echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-wireguard.conf
    echo 'net.ipv6.conf.all.forwarding=1' >> /etc/sysctl.d/99-wireguard.conf
    sysctl -p /etc/sysctl.d/99-wireguard.conf
    
    # Allow the WireGuard port through UFW
    ufw allow 51820/udp
    ufw allow OpenSSH
    ufw enable

    For MTU, WireGuard adds 60 bytes of overhead. Default tunnel MTU is 1420 (1500 minus 80 for safety). Encapsulating WireGuard inside another tunnel (rare) — drop MTU further to avoid fragmentation.

    Where Nebula and Chisel Fit Relative to WireGuard

    Nebula does not use WireGuard. It uses the Noise protocol framework (specifically Noise_IK with Curve25519). Slack built it instead of using WireGuard because they wanted certificate-based identity, group-based firewall semantics inside the tunneling layer, and an explicit decentralized model. Same problem (encrypted overlay between peers), very different architectural assumptions.

    Chisel is not a mesh tool at all. It is a reverse-tunnel utility that runs over HTTP and WebSocket. The reason it appears in this series is that the same set of users evaluating Netbird and Pangolin frequently end up reaching for Chisel for the small set of cases where a full mesh is overkill.

    Decision Tree to Read the Rest of the Series

    • • You want the easiest self-hosted mesh with SSO: Part 2 (Netbird).
    • • You want kernel WireGuard performance and granular topology control: Part 3 (Netmaker).
    • • You want no control plane in the runtime path and certificate-based identity: Part 4 (Nebula).
    • • You want a self-hosted alternative to Cloudflare Tunnel: Part 5 (Pangolin section).
    • • You want a single-binary ad-hoc TCP/UDP tunnel: Part 5 (Chisel section).
    • • You are still deciding: skip to Part 6.