WireGuard is a modern VPN protocol: a minimal config, a fast handshake and
modern crypto out of the box. The scenario of this article: a server with the
address 10.0.0.1 in the VPN network and a client 10.0.0.2.
Installation#
sudo apt update
sudo apt install wireguard
The wireguard kernel module loads automatically when the interface first
comes up — nothing to do manually.
Keys#
Every node has its own pair: a private key (never shown to anyone) and a public one (exchanged with the peer). On the server:
sudo -i
cd /etc/wireguard
# A closed umask for the folder and keys: the private key must not be world-readable
umask 077
# Private key → public
wg genkey > server.key
wg pubkey < server.key > server.pub
On the client — the same two commands: client.key / client.pub.
The client's public key goes into the server's
[Peer]— and vice versa. Private keys never leave their machine.
Server configuration#
/etc/wireguard/wg0.conf:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <server.key>
# The client with its public key and VPN address
[Peer]
PublicKey = <client.pub>
AllowedIPs = 10.0.0.2/32
For full-tunnel clients to reach the internet through the server, you need forwarding and NAT:
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf
# An addition into [Interface] of wg0.conf (eth0 — your external interface)
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
Client configuration#
wg0.conf on the client machine:
[Interface]
Address = 10.0.0.2/24
PrivateKey = <client.key>
[Peer]
PublicKey = <server.pub>
Endpoint = <server-IP>:51820
# 0.0.0.0/0 — all traffic through the tunnel
# To route only server subnets through the VPN, specify them instead:
# AllowedIPs = 10.0.0.0/24
AllowedIPs = 0.0.0.0/0, ::/0
# Keep the NAT translation alive
PersistentKeepalive = 25
Bringing it up#
# Bring the tunnel up
sudo wg-quick up wg0
# State: data exchange, handshakes, roaming
sudo wg
# Bring it down
sudo wg-quick down wg0
wg showalso shows the latest handshake and how many bytes went through a peer — that's where you see the key pair is working.
Autostarting the interface at boot — regular systemd unit semantics
(wg-quick@<interface-name>):
sudo systemctl enable --now wg-quick@wg0
Firewall#
# UDP port only
sudo ufw allow 51820/udp
The key difference from OpenVPN: WireGuard speaks UDP only — the protocol has no TCP mode.
A lifehack: a client on the phone#
The config is best handed over as a QR code — the official app (iOS/Android) scans it:
sudo apt install qrencode
qrencode -t ansiutf8 < wg0.conf
Every device gets its own [Peer] with its own private key and address:
configs are not shared between devices.