The Tunnel Home: Reaching Your Homelab from Anywhere with WireGuard

A modern VPN that fits in a single config file

Picture the scene: you are on a train, you want to check a service running at home, and your options are to expose that service to the entire internet or to go without. For years the answer to this dilemma was a clunky VPN that took an afternoon to configure and never quite behaved on mobile. WireGuard changes the calculus completely. It is a modern virtual private network so lean that its entire configuration fits in a file you can read at a glance, fast enough that you forget it is there, and secure enough that it has been merged into the Linux kernel itself. This guide builds a WireGuard tunnel from scratch so you can reach your homelab from anywhere without exposing a single service to the open web.

The temptation is always to forward a port and be done with it. Resist it. The moment a service listens on the public internet, it is found, often within minutes, by automated scanners that probe every address relentlessly. A single unpatched vulnerability, a weak password, or a misconfiguration in any one of those exposed services becomes a doorway into your network.

A VPN flips the model. Instead of poking individual holes for each service, you create one encrypted entry point that only authenticated peers can use. Once connected, you reach your internal services as though you were sitting at home, but to the outside world there is nothing to attack except the VPN itself, and WireGuard’s attack surface is famously tiny. Fewer doors, all of them strong, is the whole philosophy.

OpenVPN served us faithfully for two decades, but it shows its age. Its codebase is large, its configuration sprawling, and its performance modest because much of its work happens in user space. WireGuard was designed as a deliberate reaction to all of that.

The differences are stark in practice. WireGuard’s entire codebase is a few thousand lines, small enough to be audited in full, against OpenVPN’s hundreds of thousands. It runs in the Linux kernel, which makes it noticeably faster and lower-latency. It uses a fixed, modern set of cryptographic primitives rather than a sprawling menu of negotiable options, which removes whole categories of misconfiguration. And its roaming behaviour is seamless, so your phone moving between mobile data and Wi-Fi does not drop the tunnel. The one thing OpenVPN still does better is blend into hostile networks that block VPNs, but for reaching your own homelab, WireGuard wins comfortably.

WireGuard is built from a few simple ideas. Every participant, server or client, is called a peer, and each peer has a key pair: a private key it keeps secret and a public key it shares. A peer authenticates another by recognising its public key, exactly like SSH keys. There are no usernames or passwords in the protocol at all.

The other concept that trips people up is AllowedIPs. On a peer’s configuration, this serves two roles at once: it defines which source addresses are accepted from that peer, and it defines which destination addresses get routed through the tunnel to it. Get these right and everything flows; get them wrong and traffic silently vanishes. Keep that dual meaning in mind and WireGuard stops being mysterious.

On a Debian or Ubuntu server, install the tools:

sudo apt update
sudo apt install wireguard

Generate the server’s key pair, keeping the private key readable only by root:

cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

Now create /etc/wireguard/wg0.conf. This defines the tunnel interface, gives the server an address inside a private VPN subnet, and listens on a UDP port:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>

[Peer]
# Your phone or laptop
PublicKey = <client public key, generated next>
AllowedIPs = 10.8.0.2/32

The server lives at 10.8.0.1, the first client will be 10.8.0.2, and the AllowedIPs of 10.8.0.2/32 tells the server that only that single address belongs to that peer.

On the client, or on the server if you prefer to generate everything centrally, create a key pair the same way:

wg genkey | tee client_private.key | wg pubkey > client_public.key

Take the client’s public key and paste it into the server’s [Peer] block from the previous step. Then build the client’s own configuration file:

[Interface]
Address = 10.8.0.2/24
PrivateKey = <contents of client_private.key>
DNS = 10.8.0.1

[Peer]
PublicKey = <server public key>
Endpoint = your-home-public-ip:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Setting AllowedIPs = 0.0.0.0/0 routes all of the client’s traffic through the tunnel, which is the safest choice on untrusted networks. If you only want to reach your home subnet and leave normal browsing alone, set it to something like 10.8.0.0/24, 192.168.1.0/24 instead. The PersistentKeepalive line keeps the tunnel alive through home routers that would otherwise drop the connection.

For the server to pass traffic from VPN clients onward to the rest of your network or the internet, the Linux kernel must be allowed to forward packets, and outbound traffic must be translated. First enable forwarding permanently:

echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system

Then add NAT and firewall rules. The tidiest approach is to put them directly in the WireGuard config so they apply and clean up automatically with the interface. Add these lines to the server’s [Interface] section, replacing eth0 with your real outbound interface:

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Finally, make sure your home router forwards UDP port 51820 to this server, and bring the tunnel up:

sudo systemctl enable --now wg-quick@wg0
sudo wg show

The wg show command is your dashboard; it lists each peer and, once a client connects, the time of the latest handshake.

WireGuard’s mobile apps make client setup painless. Rather than typing a config on a tiny keyboard, install a QR-code tool on the server and render the client configuration as an image:

sudo apt install qrencode
qrencode -t ansiutf8 < client.conf

A block of pixel art appears in your terminal. Open the official WireGuard app on the phone, choose to add a tunnel by scanning a QR code, point the camera at the screen, and the entire configuration imports in one go. Toggle the tunnel on and your phone is now, for all intents and purposes, on your home network.

Almost every problem reduces to a handshake that never completes, and there are only a few usual causes. If wg show reports no recent handshake, work through them in order: confirm the router is forwarding the UDP port to the correct internal machine; verify the client’s Endpoint points at your real public IP, not a stale or private one; check that each peer holds the other’s correct public key, since a single wrong character breaks everything silently. Watch that the VPN subnet does not collide with the network you are connecting from, because two networks both using 192.168.1.0/24 will confuse the routing. And remember WireGuard is silent by design: it sends nothing until there is traffic, so a tunnel can look idle yet be perfectly healthy until you actually use it.

WireGuard delivers something rare in security tooling: it is both stronger and simpler than what it replaces. A handful of keys, a config file you can hold in your head, and a single guarded entry point give you the freedom to reach your homelab from a train, a café, or the other side of the world without ever exposing your services to the scanners that prowl the internet. Set it up once, scan a QR code onto your phone, and the tunnel home is always quietly waiting.