Tutorials

Build a WireGuard VPN

You may want to review the typographical conventions used on this site.

Install WireGuard

Install the WireGuard packages and dependencies. On non-amd64 computers, adjust the linux-headers-amd64 package to match your architecture.

apt-get install build-essential linux-headers-amd64 dkms
apt-get install wireguard-tools wireguard-dkms wireguard

Configure WireGuard

For the purposes of this tutorial, the following example network will be used:

Example Network

Generate Per-Peer Asymmetric Keys

Each WireGuard peer requires a unique public-private key pair. The following command pipeline will generate a private key, and then generate a public key for that private key. Execute these commands on each WireGuard peer to generate a unique key pair for that peer.

umask 077
wg genkey | tee private.key | wg pubkey > public.key

Since there are four WireGuard peers in this tutorial, four key pairs are required:

The private.key and public.key files can be deleted once their contents have been copied into the relevant configuration files.

Generate Per-Tunnel Pre-Shared Keys

For additional security, each WireGuard tunnel can add a unique pre-shared key (PSK). Execute the following command to generate each PSK.

wg genpsk

Since there are three WireGuard tunnels in this tutorial, three PSKs are required:

Configuration Files

Gateway-1 (GW1)

Gateway-1: /etc/wireguard/wg0.conf

[Interface]
#PublicKey = GW1_PublicKey
PrivateKey = GW1_PrivateKey
ListenPort = 4510
Address = 192.168.11.1/24, fd1e:6fe0:5044:420b::1/64

# Peer: Gateway-2
[Peer]
PublicKey = GW2_PublicKey
PresharedKey = GW1_GW2_PSK
AllowedIPs = 192.168.20.0/23, fd1e:6fe0:5044:4214::/63
Endpoint = GW2_PUBLIC_IP:4510

# Peer: Alice's laptop
[Peer]
PublicKey = ALICE_PublicKey
PresharedKey = GW1_ALICE_PSK
AllowedIPs = 192.168.11.10/32, fd1e:6fe0:5044:420b::a/128

For the Gateway-2 peer, AllowedIPs contains all IP address space at Site-2: 192.168.20.0/23 contains both 192.168.20.0/24 and 192.168.21.0/24, and fd1e:6fe0:5044:4214::/63 contains both fd1e:6fe0:5044:4214::/64 and fd1e:6fe0:5044:4215::/64.

For simple endpoint peers, such as Alice’s laptop, AllowedIPs contains the specific IPv4 and IPv6 addresses for that peer.

Gateway-1 is also running a DNS recursive resolver that is listening on addresses 192.168.11.1 and fd1e:6fe0:5044:420b::1.

Gateway-2 (GW2)

Gateway-2: /etc/wireguard/wg0.conf

[Interface]
#PublicKey = GW2_PublicKey
PrivateKey = GW2_PrivateKey
ListenPort = 4510
Address = 192.168.21.1/24, fd1e:6fe0:5044:4215::1/64

# Peer: Gateway-1
[Peer]
PublicKey = GW1_PublicKey
PresharedKey = GW1_GW2_PSK
AllowedIPs = 192.168.10.0/23, fd1e:6fe0:5044:420a::/63
Endpoint = GW1_PUBLIC_IP:4510

# Peer: Bob's laptop
[Peer]
PublicKey = BOB_PublicKey
PresharedKey = GW2_BOB_PSK
AllowedIPs = 192.168.21.10/32, fd1e:6fe0:5044:4215::a/128

For the Gateway-1 peer, AllowedIPs contains all IP address space at Site-1: 192.168.10.0/23 contains both 192.168.10.0/24 and 192.168.11.0/24, and fd1e:6fe0:5044:420a::/63 contains both fd1e:6fe0:5044:420a::/64 and fd1e:6fe0:5044:420b::/64.

For simple endpoint peers, such as Bob’s laptop, AllowedIPs contains the specific IPv4 and IPv6 addresses for that peer.

Gateway-2 is also running a DNS recursive resolver that is listening on addresses 192.168.21.1 and fd1e:6fe0:5044:4215::1.

Alice

Alice’s laptop: /etc/wireguard/wg0.conf

[Interface]
#PublicKey = ALICE_PublicKey
PrivateKey = ALICE_PrivateKey
Address = 192.168.11.10/32, fd1e:6fe0:5044:420b::a/128
DNS = 192.168.11.1, fd1e:6fe0:5044:420b::1

# Peer: Gateway-1
[Peer]
PublicKey = GW1_PublicKey
PresharedKey = GW1_ALICE_PSK
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = GW1_PUBLIC_IP:4510

Bob

Bob’s laptop: /etc/wireguard/wg0.conf

[Interface]
#PublicKey = BOB_PublicKey
PrivateKey = BOB_PrivateKey
Address = 192.168.21.10/32, fd1e:6fe0:5044:4215::a/128
DNS = 192.168.21.1, fd1e:6fe0:5044:4215::1

# Peer: Gateway-2
[Peer]
PublicKey = GW2_PublicKey
PresharedKey = GW2_BOB_PSK
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = GW2_PUBLIC_IP:4510

Control WireGuard

On peers such as VPN gateways, configure systemd to automatically start the wg0 interface.

systemctl daemon-reload
systemctl start wg-quick@wg0.service
systemctl enable wg-quick@wg0.service

On other peers, you can manually bring the wg0 interface up and down on an as-needed basis.

wg-quick up wg0
wg-quick down wg0

To show the current status of all WireGuard interfaces:

wg show

Tags: <a href="/tags/encryption">encryption</a>, <a href="/tags/privacy">privacy</a>, <a href="/tags/security">security</a>, <a href="/tags/vpn">VPN</a>, <a href="/tags/wireguard">WireGuard</a>