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:
- This website
- Rental applications for my properties (each LLC has its own)
- Git server
- Syncthing nodes (on VPN)
- Mediawiki (on VPN)
- Plex (on VPN)
For setting up Wireguard, there’s a couple of different types of peer configurations:
- The gateway
- A server for fulfilling requests (in my case, behind NAT)
- A client that connects to a server
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!