$ vim /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
define WAN_IFC = eth0
define VPN_IFC = wg0
define VPN_NET = 10.10.10.0/24
define VPN_SERVICES = { 10.10.10.20, 10.10.10.21 }
table inet filter {
chain input {
...
# Wireguard VPN
udp dport 51820 counter accept comment "Allow VPN"
iifname $VPN_IFC udp dport 53 ip saddr $VPN_NET counter accept comment "Allow DNS for VPN"
# Allow VPN clients to communicate with each other.
# iifname $vpn oifname $vpn ct state new accept
...
chain forward {
...
# forward WireGuard traffic, allowing it to access internet via WAN
iifname $VPN_IFC oifname $WAN_IFC ct state new counter accept
...
table inet nat {
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
# masquerade wireguard traffic
# make wireguard traffic look like it comes from the server itself
oifname $WAN_IFC ip saddr $VPN_NET counter masquerade comment "Masquerade VPN traffic"
...
To reload rules from the config file, use:
$ systemctl restart nftables.service
$ apt install wireguard wireguard-tools
Generate the keys:
$ wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
Edit the configuration file and enter the peers. You can obtain peer public key from the wireguard client running on the specific peer.
$ vim /etc/wireguard/wg0.conf
[Interface]
Address = 10.10.10.1/24
SaveConfig = true
ListenPort = 51820
PrivateKey = xxxxxxxxxxxx_SERVER_PRIVATE_KEY_xxxxxxxxxxxxxx
[Peer]
PublicKey = xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
AllowedIPs = 10.10.10.3/32
[Peer]
PublicKey = xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
AllowedIPs = 10.10.10.4/32
Secure the keys and configuration files
$ chmod 600 /etc/wireguard/ -R
Start the service:
$ systemctl start wg-quick@wg0.service
Enable service at boot:
$ systemctl enable wg-quick@wg0.service
Check status:
$ wg
interface: wg0
public key: xxxxxxxxxxxx_SERVER_PUBLIC_KEY_xxxxxxxxxxxxxx
private key: (hidden)
listening port: 51820
peer: xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
endpoint: x.x.x.x:49810
allowed ips: 10.10.10.4/32
latest handshake: 1 minute, 1 second ago
transfer: 108.77 KiB received, 221.66 KiB sent
peer: xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
endpoint: x.x.x.x:59302
allowed ips: 10.10.10.3/32
All good, but we don’t know exactly which peer is which. So use friendly names script:
$ cd /usr/local/bin
$ wget https://raw.githubusercontent.com/FlyveHest/wg-friendly-peer-names/master/wgg.sh
$ chmod a+x wgg.sh
$ mv wgg.sh wgg
$ cd /etc/wireguard
Create a key to peer name dictionary:
$ vim peers
xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx=:phone
xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx=:laptop
Now we can use wgg
to display prettier status:
$ wgg
interface: wg0
public key: xxxxxxxxxxxx_SERVER_PUBLIC_KEY_xxxxxxxxxxxxxx
private key: (hidden)
listening port: 51820
peer: xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
name: phone
endpoint: x.x.x.x:49810
allowed ips: 10.10.10.4/32
latest handshake: 1 minute, 3 seconds ago
transfer: 108.77 KiB received, 221.66 KiB sent
peer: xxxxxxxxxxxx_PEER_PUBLIC_KEY_xxxxxxxxxxxxxx
name: laptop
endpoint: x.x.x.x:59302
allowed ips: 10.10.10.3/32