WireGuard — Secure VPN Tunnel
Terminal, Security, Network
Overview
WireGuard1 is a modern VPN protocol that creates encrypted tunnels between peers using state-of-the-art cryptography. Unlike legacy solutions such as OpenVPN or IPsec, it is designed to be faster, simpler, and easier to audit — the entire codebase fits in roughly 4,000 lines of C.
WireGuard operates over UDP and establishes connections only when traffic needs to flow, keeping idle tunnels silent. Each peer is identified by a public key, similar to SSH, eliminating the complexity of certificate authorities and pre-shared keys. It supports both peer-to-peer and server-client topologies, making it suitable for everything from remote access to site-to-site networking.
WireGuard vs SSH-Based Alternatives
SSH tunneling has long been the go-to method for quickly creating secure connections. Tools like sshuttle2 extend this idea by intercepting traffic at the network layer and proxying it over SSH, acting as a poor man’s VPN without requiring admin access on the remote side. Yet both approaches share a fundamental limitation: they tunnel everything over a single SSH connection.
| Dimension | SSH Tunnel | sshuttle | WireGuard |
|---|---|---|---|
| Layer | Application (port forwarding) | Network-layer interception proxied over SSH | Network layer (kernel TUN device) |
| Scope | Single host or specific forwarded ports | Entire subnets routed through one SSH session | Entire subnets; full mesh between peers |
| Performance | Userspace encryption; per-port connections degrade under load | Single SSH connection becomes a bottleneck; TCP-over-TCP latency | Kernel-mode crypto; near-wire-speed throughput |
| Topology | Client-server only | Client-server only | Peer-to-peer and server-client; any peer can initiate |
| Admin required | No | No on the remote side | Yes, to install and configure WireGuard |
| DNS | Manual forwarding or -D SOCKS proxy |
Built-in DNS tunneling over SSH | Routes DNS like any other traffic |
When you need quick access to a remote network without admin privileges, sshuttle is the practical choice. It intercepts traffic destined for specified subnets and forwards it over SSH, handling DNS automatically. The drawback is that all traffic funnels through a single SSH connection — if that connection drops, everything goes down. Performance suffers under heavy load because SSH encrypts in userspace and stacks TCP over TCP.
WireGuard handles multi-host networking naturally. Every peer on the tunnel can reach every other peer directly, with no hub-and-spoke bottleneck. The trade-off is that you need to deploy and configure WireGuard on both ends — it does not reuse your existing SSH keys or daemon.
Installation
The WireGuard kernel module is included in the mainline Linux kernel since version 5.6, so every current Fedora release has it built in. You only need the userspace tools to manage tunnels and handle configuration.
Install the package from the default repositories:
sudo dnf install -y wireguard-tools| Binary | Purpose |
|---|---|
wg |
Configure and inspect WireGuard interfaces |
wg-quick |
Bring interfaces up or down using a configuration file |
Verify the installation and confirm the kernel module is available:
wg --version
modprobe wireguard
lsmod | grep wireguardThe modprobe command loads the module immediately. The lsmod output confirms it is active and ready before you create any tunnel interfaces.
On Fedora Workstation, you can also manage WireGuard through NetworkManager, which integrates with GNOME’s network settings panel. Import an existing configuration file with:
sudo nmcli connection import type wireguard file /etc/wireguard/wg0.confThis approach is optional. The wg-quick method works on both servers and desktops and gives you more control over the tunnel lifecycle.
Usage
Key Generation
Each peer in a WireGuard tunnel needs a private key and a corresponding public key. The keys are 32-byte values encoded in base64, derived from the Curve25519 elliptic curve3.
Generate a private key:
wg genkeyDerive the matching public key from it:
wg genkey | wg pubkeyGenerates both keys at once, saving the private key to a file while piping it through wg pubkey:
wg genkey | tee private.key | wg pubkey > public.key
chmod 600 private.keyConfiguration
Once the client has generated its key pair, share only the public key with the server. The private key stays on the client machine and never leaves it. On the server, register the client as a peer by adding a [Peer] block to /etc/wireguard/wg0.conf:
[Peer]
PublicKey = <client-public-key>
AllowedIPs = 10.0.0.2/32The PublicKey field authenticates the client. The AllowedIPs field assigns the client a tunnel IP address and defines which traffic from that IP is accepted. Use a /32 CIDR mask for individual hosts.
Apply the change without disrupting existing peers:
sudo wg set wg0 peer <client-public-key> allowed-ips 10.0.0.2/32
sudo wg-quick save wg0The wg set command updates the live interface immediately. The wg-quick save command persists the runtime configuration back to the config file so it survives a reboot.
Create the client configuration file at /etc/wireguard/wg0.conf on the client machine4:
[Interface]
Address = 10.0.0.2/24
PrivateKey = <client-private-key>
DNS = 1.1.1.1
[Peer]
PublicKey = <server-public-key>
Endpoint = <server-ip>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25The Endpoint field specifies the server’s reachable address and port. The AllowedIPs = 0.0.0.0/0, ::/0 directive routes all IPv4 and IPv6 traffic through the tunnel. For split tunneling, replace it with specific CIDR ranges such as 10.0.0.0/24. The PersistentKeepalive setting sends a heartbeat every 25 seconds to keep NAT mappings alive when idle.
Start the tunnel on the client:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0Verify the connection with sudo wg. The output shows peer status, data transfer counters, and the time since the last handshake.
Footnotes
WireGuard Project
https://www.wireguard.com/↩︎wg(8) — Linux manual page
https://www.man7.org/linux/man-pages/man8/wg.8.html↩︎wg-quick(8) — configuration file format
https://www.man7.org/linux/man-pages/man8/wg-quick.8.html↩︎