This article shall go through installation procedure of wireguard-tools for debian-based and arch-based distro, key generation, and configuration.
Then an example case is presented to elucidate how to configure one in a production environment.
For simplicity reasons, this article shall also assumes the use of UFW for its firewall, and systemd for its init system.
Problem Statement
To prevent the outside world from accessing an internal network, while allowing hosts from the internal network to communicate with one another, a server-host architecture is selected. This configuration requires one public IP from which all other hosts connect to, and through which all traffics are routed from one host to the other. The host with a public IP is the Gateway (or traditionally a VPN Server), while the other hosts are Clients in this model.
Installation
For a debian-based distro, use the following command to install:
sudo apt install wireguard-tools
For an arch-based distro, use the following command to install:
sudo pacman -S wireguard-tools
This command would provide wg command and wg-quick command.
It would also provide [email protected] systemd unit to selectively enable and run wireguard configurations located in /etc/wireguard/*.conf.
Key Generation
There are two kinds of keys to be generated: asymmetric and symmetric keys. The first one is a typical public key and private key pair generation. The latter one is a preshared key, acting as a secondary quantum resistant symmetric cryptography.
Assume we have the following hostnames where server is the hostname of our server, and client is the name of our client:
GATEWAY=server
PEER=client
Note that the hostnames are arbitrary and they are only used for identification (as in, to avoid keys mix-up when composing config files).
To generate a private key:
(umask 0077; wg genkey > "${GATEWAY}".key)
To generate a public key:
wg pubkey < "${GATEWAY}".key > "${GATEWAY}".pub
Alternately, one can generate both public key and private key simultaneously:
wg genkey | (umask 0077 && tee "${PEER}".key) | wg pubkey > "${PEER}".pub
The resulting files (ending in .key and .pub) are private key and public key respectively.
Their content shall be used on crafting the wireguard configuration.
Then to generate a preshared key, one would run the following:
(umask 0077 && wg genpsk > "${GATEWAY}-${PEER}".psk)
Once everything is ready, one can continue to craft the configuration files.
Configuration
The convention for devices in a private IPv4 network is to use 10.0.0.0/8 (address range from 10.0.0.0 to 10.255.255.255). Therefore to make a simple client server structure, the following configuration is desired:
- Gateway: 10.25.79.1/32
- Peers: 10.25.79.0/24 # allows range of 10.25.79.{0..255}
- alpha: 10.25.79.2/32
- beta: 10.25.79.3/32
- gamma: 10.25.79.4/32
There should be at least two types of configuration pattern:
- The Gateway configuration, which involves listen port of the interface, and the FORWARD rules to be used for the connection, then a list of ALL peers connected to the private network.
- The Peer configuration, which differs only in the interface address, interface private key, and peer preshared key.
Below is an example implementation of a gateway config:
# On gateway, file /etc/wireguard/wg0.conf
[Interface]
Address = 10.25.79.1/24, 2c4d:a1:a2::a5:0:1/64
ListenPort = 51504
PrivateKey = GATEWAY_PRIVATE_KEY
# substitute eth0 in the following lines to match
# the Internet-facing interface.
# The FORWARD rules will always be needed since
# traffic needs to be forwarded between the WireGuard
# interface and the other interfaces on the server.
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer] # Peer alpha
PublicKey = PEER_ALPHA_PUBLIC_KEY
PresharedKey = GATEWAY_TO_PEER_ALPHA_PRESHARED_KEY
AllowedIPs = 10.25.79.2/32, 2c4d:a1:a2::a5:0:2/128
[Peer] # Peer beta
PublicKey = PEER_BETA_PUBLIC_KEY
PresharedKey = GATEWAY_TO_PEER_BETA_PRESHARED_KEY
AllowedIPs = 10.25.79.3/32, 2c4d:a1:a2::a5:0:3/128
[Peer] # Peer gamma
PublicKey = PEER_GAMMA_PUBLIC_KEY
PresharedKey = GATEWAY_TO_PEER_GAMMA_PRESHARED_KEY
AllowedIPs = 10.25.79.4/32, 2c4d:a1:a2::a5:0:4/128
Then the peers would have the following configuration file:
# On Peer alpha, file /etc/wireguard/wg0.conf
[Interface]
Address = 10.25.79.2/32, 2c4d:a1:a2::a5:0:2/128
PrivateKey = PEER_ALPHA_PRIVATE_KEY
[Peer] # Peer A
PublicKey = GATEWAY_PUBLIC_KEY
PresharedKey = GATEWAY_TO_PEER_ALPHA_PRESHARED_KEY
Endpoint = example.org:51504
AllowedIPs = 10.25.0.0/16, 2c4d:a1:a2:0::/64
PersistentKeepalive = 21
Pay attention to the following placeholders:
GATEWAY_PRIVATE_KEY: gateway private keyGATEWAY_PUBLIC_KEY: gateway public keyPEER_ALPHA_PRIVATE_KEY: peer alpha’s private keyPEER_ALPHA_PUBLIC_KEY: peer alpha’s public keyGATEWAY_TO_PEER_ALPHA_PRESHARED_KEY: preshared key for gateway-alpha connection
Adjust the values according to your actual keys. The configuration should be similar for other peers.
Note that in the examples above, IPv6 addresses are also included. However IPv6 addresses are optional, one may entirely omit them as needed.
The AllowedIPs for Peer B uses 10.25.0.0/16 because we allow connection only from 10.25.0.0 to 10.25.255.255.
The /16 section is how many bits are reserved for the address, and it indicates two 8 bits segments are reserved (the 10.25 bits).
Therefore, assuming 0 could mean any number from 0 to 255, and the rest are reserved (meaning they would not and should not change).
Therefore the following examples have to be interpreted as:
10.0.0.0/8: Only the first 8 bits segments is reserved, representing IPv4 address range from10.0.0.0up to10.255.255.255.10.0.0.0/16: Only the first 16 bits segments is reserved, representing IPv4 address range from10.0.0.0up to10.0.255.255.10.0.0.0/24: Only the first 24 bits segments is reserved, representing IPv4 address range from10.0.0.0up to10.0.0.255.10.0.0.0/32: All segments are reserved, representing only the IPv4 address of10.0.0.0.
Or more succintly:
10.25.79.1/32
10.25.79.0/24
10.25.0.0/16
10.0.0.0/8
For IPv6 addresses, it should be 128-bits in length.
wg-quick
Since the example system assumes the use of systemd as the system’s init, and that the example configuration’s location is at /etc/wireguard/wg0.conf (for each hosts), the connection can be activated with:
systemctl enable --now [email protected]
The wg0 bit is arbitrary, one can select any other names as necessary (eg. ring1 with ring1.conf, tunnel with tunnel.conf, and home-network with home-network.conf).
One can have different names, or even multiple wireguard configurations as many as needed.
If the init system is not systemd, adjust the unit files accordingly.
- Up command:
wg-quick up wg0 - Down command:
wg-quick down wg0 - Reload command:
/bin/bash -c 'exec /usr/bin/wg syncconf wg0 <(exec /usr/bin/wg-quick strip wg0)'
References
- Arch Linux Wiki - WireGuard. This article is heavily adapted from Arch Linux Wiki’s page on WireGuard. The author’s contribution includes setting an actual use case of a very basic setup, including materials not originally found in the wiki article.