In 2012, I wrote an article on how to set up a VPN using OpenVPN. With so many companies offering VPN services nowadays, I thought it would be a good idea to run your own VPN service; however, WireGuard is a much better fit for this goal.
WireGuard is a modern VPN protocol built into the Linux kernel since version 5.6. Compared to OpenVPN, it is significantly simpler to configure, faster, and has a much smaller attack surface (~4000 lines of code vs ~100,000 for OpenVPN).
Prefer OpenVPN? See How to set up an OpenVPN server and client on Linux.
How WireGuard works
WireGuard uses public/private key pairs — similar to SSH keys. Each peer (server or client) has its own key pair. You add a peer's public key to your config, and WireGuard handles the rest. There are no certificates, no CA, no certificate revocation lists.
Install WireGuard
Debian / Ubuntu (kernel 5.6+, most current installs):
sudo apt install wireguard
RHEL / Fedora / Rocky Linux:
sudo dnf install wireguard-tools
Server setup
1. Generate server keys
wg genkey | tee server_private.key | wg pubkey > server_public.key
Keep server_private.key secret. You will share server_public.key with clients.
2. Create the server config
Create /etc/wireguard/wg0.conf:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>
# Enable routing — forward all client traffic through this server
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Replace eth0 with your server's public network interface (check with ip link show).
3. Enable IP forwarding
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
4. Start WireGuard
sudo systemctl enable --now wg-quick@wg0
sudo systemctl status wg-quick@wg0
Client setup
1. Generate client keys
Run this on the client machine:
wg genkey | tee client_private.key | wg pubkey > client_public.key
2. Add the client as a peer on the server
Append to /etc/wireguard/wg0.conf on the server:
[Peer]
PublicKey = <contents of client_public.key>
AllowedIPs = 10.0.0.2/32
Reload the server config without dropping existing connections:
sudo wg syncconf wg0 <(wg-quick strip wg0)
3. Create the client config
Create /etc/wireguard/wg0.conf on the client:
[Interface]
Address = 10.0.0.2/24
PrivateKey = <contents of client_private.key>
DNS = 1.1.1.1
[Peer]
PublicKey = <contents of server_public.key>
Endpoint = 12.34.56.78:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0routes all traffic through the VPNPersistentKeepalive = 25keeps the tunnel alive through NAT
4. Start the client
sudo systemctl enable --now wg-quick@wg0
Verify the connection
On the server, check connected peers and traffic:
sudo wg show
On the client, verify your public IP has changed:
curl ifconfig.me
Add more clients
Repeat the client steps for each new device. Generate a new key pair, assign a new IP (10.0.0.3/32, 10.0.0.4/32, etc.), and add a [Peer] block to the server config.
WireGuard vs OpenVPN
| WireGuard | OpenVPN | |
|---|---|---|
| Configuration | Simple key pairs | PKI with CA and certificates |
| Speed | Very fast (kernel-level) | Slower (userspace) |
| Code size | ~4,000 lines | ~100,000 lines |
| Kernel integration | Built-in (Linux 5.6+) | Module or userspace |
| Mobile support | Excellent (official apps) | Good |
| Audit history | Audited 2017 | Long track record |
| Best for | Most new setups | Complex enterprise PKI needs |
See also
- How to set up an OpenVPN server and client on Linux
man wgandman wg-quick— full reference