Using WireGuard for Site-to-Site VPN
WireGuard is a modern VPN protocol that is designed to be fast, secure, and easy to configure. In this note, I will show you how to set up a site-to-site VPN using WireGuard.
Install required packages:
apt install -qy wireguard wireguard-tools
Generate the private and public keys for the server:
mkdir -p /etc/wireguard/keys
wg genkey | tee /etc/wireguard/keys/wg-s2s.private.key | wg pubkey > /etc/wireguard/keys/wg-s2s.public.key
[Interface]
PrivateKey = <payload from /etc/wireguard/keys/wg-s2s.private.key>
ListenPort = 1024
Address = 169.254.20.1/32
SaveConfig = false
Add the peer configuration (another server):
[Peer]
PublicKey = <payload from another server>
AllowedIPs = 169.254.20.2/32
Endpoint = 192.0.2.1:1024
PersistentKeepalive = 20
Example configuration
In this example, let’s create connect from the office to AWS with 3 aviablity zones.
Create file: /etc/wireguard/wg-s2s.conf
[Interface]
PrivateKey = <payload from /etc/wireguard/keys/wg-s2s.private.key>
Address = 169.254.20.129/32
SaveConfig = false
# AWS us-west-2a
[Peer]
PublicKey = <public key from us-west-2a>
Endpoint = <EC2 public IP>:1024
PersistentKeepalive = 10
AllowedIPs = 168.254.20.1/32,172.30.0.0/22
# AWS us-west-2b
[Peer]
PublicKey = <public key from us-west-2b>
Endpoint = <EC2 public IP>:1024
PersistentKeepalive = 10
AllowedIPs = 168.254.20.2/32,172.30.4.0/22
# AWS us-west-2c
[Peer]
PublicKey = <public key from us-west-2c>
Endpoint = <EC2 public IP>:1024
PersistentKeepalive = 10
AllowedIPs = 168.254.20.3/32,172.30.8.0/22
After enable and start the WireGuard service:
systemctl enable wg-quick@wg-s2s.service
systemctl start wg-quick@wg-s2s.service
Example from AWS side
[Interface]
PrivateKey = <payload from /etc/wireguard/keys/wg-s2s.private.key>
Address = 168.254.20.1/32
ListenPort = 1024
SaveConfig = false
# office
[Peer]
PublicKey = <public key from office>
PersistentKeepalive = 10
AllowedIPs = 169.254.20.129/32,192.168.192.0/24
Small explanation
Interface:
PrivateKey
- the private key of the server. Each server must have a unique private key.ListenPort
- the port that the server listens on. We need this only for the server with a public IP. (required at least one server with a public IP). If we have a servers with public IP from both sides, we can use the same port. (same port not required, but it’s easier to manage).Address
- the IP address of the server. Or we can use this address as link-local address.
Peer:
AllowedIPs
- the list of IP addresses that are allowed to be routed through the WireGuard interface. We can use CIDR notation. Otherwise, the kernel drops the packets.Endpoint
- the public IP address of the peer. We need this only for the server with a public IP.
Enchanced Security
To enhance the security of the WireGuard VPN, we need to use PSK (Pre-Shared Key) for each peer.
Why need to have for each peer? We can easy rotate the PSK without changing the public/private keys (if we change public/private keys, we need to update all peers - it’s a pain with many peers).
Let’s create a PSK for the server:
wg genpsk > /etc/wireguard/keys/wg-s2s.psk.peer1.key
And add the PSK to the server configuration:
[Peer]
...
PresharedKey = <payload from /etc/wireguard/keys/wg-s2s.psk.peer1.key>
Dynamic routing
If we want to use dynamic routing, like BGP or Babel, we need to change the configuration of the WireGuard interface.
- We need to disable expose routing into kernel
- Allow all IPs to be routed through the WireGuard interface
[Interface]
...
Table = off
[Peer]
...
AllowedIPs = 0.0.0.0/0,::/0