ITcompressor IT — compressed and to the point
← Back to articles

WireGuard VPN

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 show also 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.

← Back to articles