Dec 15 2020

Wireguard Configurations

Lately I’ve been getting more into the self-hosted game. This DIY approach has given me a much greater appreciation for good software. It doesn’t come without its drawbacks though. Self-hosting requires more time, responsibility, planning, and various chores: data back-ups, log monitoring, ensuring good up-times, etc. It’s not a hobby to choose lightly!

If you decide to dabble with self-hosting, I recommend to start with a VPN. This can help secure an architecture from the start. While a VPN isn’t a one-stop-solution for all security problems, it does limit the attack surface. Plus, there’s the option to assign static IPs to all connected devices – giving complete control over the subnet.

Some things that I self host are:

For setting up Wireguard, there’s a couple of different types of peer configurations:

Forwarding Requests

For any devices serving requests, you will need to forward requests:

sysctl -w net.ipv4.ip_forward=1

According to the Arch Wiki, you can make this persist by adding the above to etc/sysctl.d/99-sysctl.conf.

Gateway Configuration

With the right Wireguard configuration and some firewall adjustments, you will be off to the races! You’ll notice that there is a lot of redacted info in these configurations. This speaks to Wireguard’s conciseness.

Address = 10.10.1.1/24
PrivateKey = (hidden)
ListenPort = 5555

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer] # Linux desktop
PublicKey = <<Pubkey of desktop>>

# Restrict this peer to solely 10.10.1.2 (32 subnet means 1 ip)
# This AllowedIps acts as a routing table. When we need to route traffic
# We will look up the public key by ip, encrypt, and then send to the endpoint.
# The endpoint is the last known point of access from the last connection
AllowedIPs = 10.10.1.2/32

[Peer] # raspberry pi server behind NAT
PublicKey = <<Pubkey of pi>>
AllowedIPs = 10.10.1.3/32

Linux Desktop Config

This one is simple since we are not servicing requests from inside the VPN.

[Interface]
Address = 10.10.1.2/24 # Matches address in gateway config
ListenPort = 38820
PrivateKey = (hidden)

[Peer]
PublicKey = <<Gateway public key>>
Endpoint = <<IP address of public server/gateway>>

# Only route requests from 10.10.1.* through our remote peer.
AllowedIPs = 10.10.1.0/24

Raspberry Pi Config

Besides the typical configuration, we also need the ip tables configured. This can be seen in the PostUp and PostDown. Finally, I specify a persistent keep alive timeout. The alternative would be to forward a port on your router. If you choose to do this, be sure to whitelist this to the gateway host only!

[Interface]
Address = 10.10.1.3/24 # Matches address in gateway config
ListenPort = 38820
PrivateKey = (hidden)

# Punches a hole in the firewall to accept connections on the VPN network
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]
PublicKey = <<Gateway public key>>
Endpoint = <<IP address of public server/gateway>>

# We are behind a NAT, so we need a keep alive heartbeat. Otherwise the
# connection will drop.
# If you want a less chatty solution, you can port forward for the gateway.
PersistentKeepalive = 15

# Only route requests from 172.16.0.* through our remote peer.
AllowedIPs = 10.10.1.0/24

I could create an Ansible playbook for this, but I tend to subscribe to the YAGNI principle. If I do need to reconfigure something like this, I now have this post to reference :) I hope this helps you as well!