WireGuard is so fast because it’s fundamentally simpler than older VPNs, eschewing complex cryptographic suites for a few highly optimized, modern ones.
Let’s set up a basic WireGuard tunnel between two Linux machines. We’ll call them client and server.
First, on both client and server, we need to install WireGuard. On Debian/Ubuntu systems, this is:
sudo apt update && sudo apt install wireguard
On Fedora/CentOS/RHEL:
sudo dnf install wireguard-tools
Next, we generate a private and public key pair on each machine. These are crucial for authentication.
On client:
wg genkey | tee client_privatekey | wg pubkey > client_publickey
On server:
wg genkey | tee server_privatekey | wg pubkey > server_publickey
Now, we create the WireGuard configuration file. Let’s start with server.conf on the server. This file defines the server’s private key, the IP address and port it listens on, and information about its peers (the clients).
# /etc/wireguard/server.conf
[Interface]
PrivateKey = <contents of client_privatekey on server>
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Replace <contents of client_privatekey on server> with the actual content of the server_privatekey file generated on the server. The Address is the IP the WireGuard interface on the server will have within the tunnel. ListenPort is the UDP port WireGuard will listen on. The PostUp and PostDown commands are iptables rules to enable Network Address Translation (NAT), allowing clients to access the internet through the server. eth0 should be replaced with your server’s primary public network interface.
Now, on the client, create client.conf:
# /etc/wireguard/client.conf
[Interface]
PrivateKey = <contents of client_privatekey on client>
Address = 10.0.0.2/24
DNS = 8.8.8.8
[Peer]
PublicKey = <contents of server_publickey on client>
Endpoint = <server_public_ip>:51820
AllowedIPs = 0.0.0.0/0
Replace <contents of client_privatekey on client> with the content of client_privatekey generated on the client. Replace <contents of server_publickey on client> with the content of server_publickey generated on the client. <server_public_ip> is the actual public IP address of your server machine. AllowedIPs = 0.0.0.0/0 tells the client to route all its internet traffic through the VPN. DNS = 8.8.8.8 sets the DNS server for the client’s VPN interface.
To start the WireGuard interface on the server:
sudo wg-quick up server
And on the client:
sudo wg-quick up client
You can check the status with sudo wg show. You should see handshake information if everything is working.
This setup creates a secure, encrypted tunnel. All traffic from the client destined for 0.0.0.0/0 is encapsulated, encrypted using the chosen modern ciphers (like ChaCha20-Poly1305), and sent to the server’s Endpoint. The server decrypts it, and the iptables rules route it to the internet. The server encrypts return traffic and sends it back to the client.
The most surprising thing about WireGuard is how its design philosophy of minimal complexity and modern cryptography leads to performance that often embarrasses older, more feature-rich VPN protocols. It achieves this by focusing on a small, well-vetted set of cryptographic primitives and a streamlined handshake process.
Let’s look at the AllowedIPs setting in the [Peer] section of the client configuration. While 0.0.0.0/0 routes all traffic, you can be much more specific. For instance, if you only wanted to access services on the server’s local network (say, 192.168.1.0/24) and the server itself (10.0.0.1/32), you’d set AllowedIPs = 192.168.1.0/24, 10.0.0.1/32. This means only traffic destined for these IP ranges will be sent through the WireGuard tunnel; all other traffic will go through the client’s regular internet connection. This is fundamental to how WireGuard implements split-tunneling and precise routing.
The next hurdle is often managing multiple clients, which involves generating unique keys for each, distributing their public keys to the server, and adding them as peers in the server’s configuration.