WireGuard is the VPN I deploy for every small business I migrate to Linux. Not because it is trendy, but because it is the most honest piece of networking software I have worked with in fifteen years.
In 2026, WireGuard is the default VPN protocol for a reason: it is in the mainline Linux kernel since version 5.6, independently audited, and faster than OpenVPN on the same hardware. For small businesses this means no kernel modules to maintain, no CVE backlog, and no performance complaints.
The entire trust model fits in a single config file. When something breaks, you can audit it in minutes. That matters at 8am on a Monday when a client cannot connect and you need to diagnose fast.
This is not a theoretical walkthrough. This is exactly what I deploy in production.
Before you start
- Server with static public IP
- UDP 51820 open on server firewall
- SSH access to the server
- Client machine with working internet connection
- A clear decision on whether all traffic routes through the tunnel or only the internal network (more on this below)
- A backup access plan if the tunnel breaks (physical access, out-of-band SSH, etc.)
Why WireGuard specifically
The WireGuard codebase is roughly 4,000 lines. OpenVPN's core daemon is closer to 70,000. This is not a marketing detail. Smaller codebase means smaller attack surface, faster patching, and a security posture you can actually reason about.
WireGuard has been independently audited. The Cure53 audit in 2021 and the Trail of Bits review found no critical vulnerabilities. OpenVPN has also been audited, but its larger codebase makes comprehensive auditing more time-consuming and leaves more surface area for potential issues.
I evaluated three options before standardizing on WireGuard:
OpenVPN: mature, flexible, but complex. Requires certificate management, has a larger attack surface, and is noticeably slower on low-end hardware.
IPsec/IKEv2: fast and secure, but configuration is opaque. Debugging failures often requires deep protocol knowledge.
WireGuard: minimal, audited, fast. The trade-off is manual key management, which is acceptable for teams under 20 people.
For small businesses that cannot afford enterprise security teams, choosing audited software with a minimal codebase is one of the few concrete security decisions they can make.
What you need
A Linux server you control. In my case a VPS hosted in Italy, running Debian 12. A static IP on the server side. A client machine running Linux, in most cases Kubuntu 26.04 LTS.
I use a VPS for the relay in most deployments because it gives clients a stable public IP without managing physical hardware at the office. For businesses with an on-premise server already in place, running WireGuard directly on that machine works equally well. The config is identical.
Debian 12 is the default for server deployments: predictable release cycle, five years of security updates, no surprises. I avoid rolling releases on anything client-facing.
WireGuard uses public key cryptography. Each peer generates a key pair. You exchange public keys. No certificates, no certificate authorities, no complexity that lives outside the config file.
Server setup
Install WireGuard:
apt install wireguard
Generate the server key pair. Set permissions before the key is used:
wg genkey > /etc/wireguard/privatekey
chmod 600 /etc/wireguard/privatekey
wg pubkey < /etc/wireguard/privatekey > /etc/wireguard/publickey
Create the server configuration at /etc/wireguard/wg0.conf:
[Interface]
PrivateKey = <server_private_key>
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o <interface> -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o <interface> -j MASQUERADE
[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.0.0.2/32
Replace <interface> with your actual network interface name. On Debian 12 modern installs this is typically ens3, enp1s0, or similar. Check with ip link before editing the config. Almost never eth0.
Why 10.0.0.0/24? This is RFC 1918 private space, unlikely to conflict with most office networks. I use 10.0.0.1 for the server and increment client IPs from 10.0.0.2. If your office already uses 10.0.0.0/24, choose a different range such as 10.100.0.0/24 to avoid routing conflicts.
On the /32 for each peer: this tells WireGuard that this specific public key is only allowed to use the IP 10.0.0.2. Each peer must have its own /32 entry. Without it, a compromised client could potentially spoof other addresses on the tunnel.
Note on cloud providers: if you use a VPS with a cloud security group (Hetzner, DigitalOcean, AWS), open UDP 51820 in the security group rather than via iptables. The PostUp rules above handle forwarding and NAT, not port access itself.
If your server has IPv6 enabled, which is common on modern VPS, add ip6tables rules as well:
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o <interface> -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -A FORWARD -o wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o <interface> -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o <interface> -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -D FORWARD -o wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o <interface> -j MASQUERADE
Enable IP forwarding:
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
Enable and start:
systemctl enable --now wg-quick@wg0
Client setup
Install WireGuard and openresolv:
apt install wireguard openresolv
Generate client key pair:
wg genkey > /etc/wireguard/privatekey
chmod 600 /etc/wireguard/privatekey
wg pubkey < /etc/wireguard/privatekey > /etc/wireguard/publickey
Create /etc/wireguard/wg0.conf on the client:
[Interface]
PrivateKey = <client_private_key>
Address = 10.0.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <server_public_key>
Endpoint = <server_public_ip>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Why /32 on the client? The client is a single host, not a subnet. Using /32 is semantically correct and avoids confusion when adding more clients later. The /24 on the server interface is correct because it represents the entire tunnel network.
0.0.0.0/0, ::/0 routes all traffic through the VPN, including IPv6. If you only need access to the internal network without routing everything, use the specific subnet instead, for example 10.0.0.0/24. Understand what you are routing before you route it.
PersistentKeepalive = 25 sends a keepalive every 25 seconds. Required when the client is behind NAT, which is almost always the case for small business remote workers. Without it the NAT mapping expires and the tunnel silently drops.
Enable and start:
systemctl enable --now wg-quick@wg0
Verify the tunnel:
wg show
ping 10.0.0.1
wg show confirms the handshake happened. ping 10.0.0.1 confirms the tunnel carries traffic. Both should work before you call it done.
DNS on Kubuntu 26.04 with systemd-resolved
Kubuntu 26.04 uses systemd-resolved by default. The DNS = directive in wg0.conf works correctly with systemd-resolved, but you must ensure /etc/resolv.conf points to the stub resolver:
ls -l /etc/resolv.conf
Expected output:
/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
If it points elsewhere, fix it:
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
Bring up the tunnel and verify DNS is routing correctly:
resolvectl status wg0
You should see your configured DNS listed under the wg0 interface.
Verify no DNS leaks
A DNS leak means your DNS queries are going outside the tunnel, exposing which domains you visit even if the traffic itself is encrypted. After bringing up the tunnel, verify:
dig +short myip.opendns.com @resolver1.opendns.com
This should return your VPN server's public IP, not your client's real IP. If it returns your real IP, DNS is leaking.
Also check for IPv6 leaks:
curl -6 ifconfig.co
If this returns an IP, IPv6 traffic is not going through the tunnel. Either disable IPv6 on the client or ensure ::/0 is in AllowedIPs and add an IPv6 DNS server: DNS = 1.1.1.1, 2606:4700:4700::1111.
Key management
WireGuard has no built-in key rotation. When an employee leaves or a device is compromised, you must manually remove the [Peer] block from the server config and redistribute new keys.
My workflow for small businesses: I keep a simple spreadsheet with peer name (for example "alice-laptop"), public key copied from /etc/wireguard/publickey, device owner, creation date, and last rotation date. Rotate keys every 12 to 18 months as standard practice. If a device is lost, revoke immediately: remove the [Peer] block, restart WireGuard, and generate new keys for the affected client.
This manual process is a trade-off: you gain simplicity and auditability, but lose automated lifecycle management. For teams under 20 people it is acceptable. Beyond that, consider a WireGuard management layer like Netmaker or Headscale.
Monitoring and troubleshooting
Check handshake age — should be under two minutes on an active connection:
wg show | grep "latest handshake"
Watch live traffic through the tunnel:
watch -n1 'wg show | grep transfer'
For proactive monitoring I use a simple cron job that pings the tunnel IP every 5 minutes and logs failures:
*/5 * * * * ping -c1 10.0.0.1 || logger "WireGuard tunnel down"
If the tunnel drops:
- Check logs:
journalctl -u wg-quick@wg0 - Verify the port is reachable:
nc -vzu <server_ip> 51820 - Confirm
PersistentKeepalive = 25is set on the client - Restart the tunnel:
systemctl restart wg-quick@wg0
Appendix: Kubuntu 26.04 and Wayland
Kubuntu 26.04 uses Wayland by default. This does not affect WireGuard itself, but it breaks X11-based remote desktop tools. For full remote access setups I pair WireGuard with a self-hosted RustDesk relay, which handles Wayland correctly. On Kubuntu 24.04, which still uses X11, standard remote desktop tools work without this additional step. RustDesk with a self-hosted relay is outside the scope of this guide but worth knowing before you commit to a 26.04 deployment for remote workers.
Final notes
I have been running this setup across multiple client deployments since early 2026. No security incidents, no unexplained drops. WireGuard's simplicity is its strength: when something breaks, you can read the entire config and understand it in minutes.
For small businesses migrating to Linux, this is the VPN layer I standardize on. And if a client or an auditor ever asks why I chose it, I can explain every line of the config. That is not something I could say about most alternatives.
Top comments (0)