These instructions assume that the WireGuard interface (and configuration file) will be wg0, while the machine’s main connection is eth0. Update accordingly below if they are different. The availability of iptables instead of the default firewalld is also a prerequisite.
From WireGuard’s perspective, there is no server and client – all points in a WireGuard network are called peers, and they can connect to each other without a central point and not necessarily in a star topology. However, in this particular configuration scenario and because one peer is central to my whole infrastructure (as it’s the only one to always have a static public IP address, open ports and it can also be used to tunnel all other peers’ traffic), I’m forcing things and calling it a server – while all other peers I will consider clients (and will only connect to the same one other peer which I previously called server).
Start by installing the necessary repos
dnf install epel-release elrepo-release
And continue to install WireGuard itself
dnf install kmod-wireguard wireguard-tools
Depending on the uptime of your server, this may also trigger the install of a new kernel. In this case you’ll most likely need to reboot the machine for WireGuard to be able to load its kernel module.
Tell WireGuard to create a public and private key for the server
wg genkey | sudo tee /etc/wireguard/privatekey cat /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey
Continue the setup by creating /etc/wireguard/wg0.conf with the following content:
[Interface] Address = 10.0.0.1/24 # SaveConfig = true ## this line tells wireguard to save the current configuration on stop, ## and will overwrite any changes done to the configuration file in the meantime ListenPort = 12345 PrivateKey = SERVER_PRIVATE_KEY # PublicKey = SERVER_PUBLIC_KEY ## it would be a good idea to write down the public key for future reference as well PreUp = iptables -I INPUT -p udp --dport 12345 -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE PostDown = iptables -D INPUT -p udp --dport 12345 -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
I’m using 10.0.0.0/24 as the WireGuard address space – this can be any local CIDR block of your choosing as long as it doesn’t overlap any networks already used on any of the peers.
Adjust the listen port if desired and fill in the keys from the previously generated key files. I’m not including any example keys in this tutorial because it’s a bad idea to reuse any kind of unique identifiers (especially ones available online). Always generate your own keys pairs and remember to never disclose any private keys publicly.
Test that the configuration is correct and bring up the WireGuard interface with wg-quick up wg0. You should see something similar to:
Enable WireGuard at boot with systemctl enable wg-quick@wg0
For the VPN to act as a gateway to the internet remember to enable packet forwarding on the (Linux) server by editing /etc/sysctl.conf to add
net.ipv4.ip_forward = 1
Trigger the setting by calling
sysctl -p /etc/sysctl.conf
And finally set the appropriate firewall rules (these assume the machine is using iptables):
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT
If you’re also using csf, add these rules in /etc/csf/csfpost.sh
To make changes to the wg0.conf configuration file first stop the interface with wg-quick down wg0, make the edits and then restart it with wg-quick start wg0
To check the status of the connection, use wg show wg0
Continue by creating key sets for the clients – this can be done using the wg genkey command above (remember to output them to different files) or using an online configuration generator services – (1), (2) (take security considerations into account in this case).
Add the peer details to the wg0.conf configuration file, save and restart the WireGuard interface as previously described:
[Interface] ...existing configuration... [Peer] PublicKey = PEER1_PUBLIC_KEY PresharedKey = PEER1_PRESHARED_KEY AllowedIPs = 10.0.0.2/32 [Peer] PublicKey = PEER2_PUBLIC_KEY PresharedKey = PEER2_PRESHARED_KEY AllowedIPs = 10.0.0.3/32 [Peer] PublicKey = PEER3_PUBLIC_KEY PresharedKey = PEER3_PRESHARED_KEY AllowedIPs = 10.0.0.4/32
Write down the public/private/preshared key sets, as those will be required later. The AllowedIPs parameter dictates which (unique) IP address each client (peer) is allowed to use in the virtual network. This includes both the client’s WireGuard interface IP address and any other networks that should be routed through the VPN (I’ll detail this part in the example at the end, for basic tunneling the configuration above is sufficient).
On Windows, install the WireGuard Windows client, for Android install the app from the Play Store or F-Droid. For other OSes, check out the WireGuard installation page.
As I have mentioned at the beginning, there are no clients and servers in the WireGuard topology, all endpoints are equal. This is reflected in how the configuration is done, and we’ll see that the peers I have designated as clients use almost identically structured configurations. For example, the first client’s configuration file:
[Interface] Address = 10.0.0.2/24 PrivateKey = PEER1_PRIVATE_KEY DNS = 188.8.131.52 ## optional [Peer] Endpoint = 184.108.40.206:12345 PublicKey = PEER1_PUBLIC_KEY PresharedKey = PEER1_PRESHARED_KEY AllowedIPs = 0.0.0.0/0, ::/0 ## Use this to route all traffic through the server, or AllowedIPs = 10.0.0.0/24 ## Use this to access only specific networks on the server
The DNS parameter instructs WireGuard to ignore local DNS configuration and use the set IP for DNS queries. This can be the peer (server) itself (if configured appropriately) or any other (public) DNS resolver.
The Endpoint parameter defines the other peer’s (server’s) IP address and port this client should connect to.
AllowedIPs tells WireGuard for which spaces should network traffic be routed through its interface for. The AllowedIPs setting should be either set to the address / addresses lists WireGuard expects to find on the other peer (namely its local network(s)), or instead use a special value of 0.0.0.0/0, ::/0 which instructs WireGuard to route all network traffic through the VPN.
In my own trials and errors I’ve noticed that 0.0.0.0/0 doesn’t always work as expected when trying to both tunnel traffic and access local resources on the remote peer (server), for which case a value of 0.0.0.0/1, 220.127.116.11/1 was more successful instead. There are also online calculators for when network setups become too complex.
Time to test if we’ve managed to not make a mess of all the necessary unique identifiers:
Consider the network setup below.