Info
After writing the majority of this, I’m encountering some issues with my home network staying connected to the VPS WireGuard server. I am unsure why. Last night I thought it was my terrible internet connection where I am currently staying, but doing testing from the VPS side reveals that it’s the raspberry pi.
There’s no pattern to the disconnects as far as I can tell. I had issues connecting, then randomly was able to connect into it a few minutes ago after not connecting into it all night, then it simply dropped connection again.
Pings and network scans confirm that my home network is still up, but the raspberry pi is not connected to the VPS, and there isn’t anything I can do about that until I can get someone to unplug the pi and plug it back in to restart the service.
And then it RANDOMLY started working again! This seems like it will be a project. More likely, though, it will be one line in a config file. My eyes are on PersistentKeepAlive, but I read somewhere that was unnecessary with WireGuard…I don’t remember why. I’ll have to investigate.
Recently mused about setting up a WireGuard VPN bounce server here, although I didn’t refer to it as such.
As is the case more often than not, it seems, I was overthinking it.
Thank you to these two posts for pointing me in the right direction.
- laroberto Remote LAN access with WireGuard
- laroberto Follow up for tunneled outbound VPN with WireGuard
I’ll go through the overview, then the specific setup for each machine. I’ve already covered basic WireGuard setup, key generation etc here and here, as well as briefly here, so I won’t cover that in depth.
Overview
In my previous post birthing the idea, I proposed two networks: wg0
at 10.0.10.0/24
and wg1
at 10.0.20.0/24
. Turns out I need only one network. I also had a Protectli Vault firewall running OpnSense in the diagram, which I do not (yet) own, so I opted to set up on my raspberry pi 5, on which I currently had a working WireGuard VPN.
The main difference here is instead of my raspberry pi acting as the server, it’s acting as a client, meaning I don’t have to port forward anything on the network. It’s an outbound connection to the VPN server, which then through some WireGuard AllowedIP
lines and some firewall rules, allows a client connected to the VPN to gain access to the internal network. This offloads the security concerns to the VPS instead of having an open port on my home network.
A couple other differences:
- I used my existing VPS running Debian 12, and did not spin up a new one with OpenBSD - I’ve punted that learning project a little further down the road.
- Home network IPs have remained largely the same - instead of moving the router to
10.0.0.2
I left it at10.0.0.1
and the raspberry pi at10.0.0.2
. WireGuard VPS IP is10.0.20.1/24
. - As I do not have direct access to my LAN at the moment, I left
wg0
and the51820
port forward alone on my pi, as a fallback plan if I messed upwg1
.
Updated diagram
Some helpful commands
Setup on VPS server
Very similar to the previous setups. Key difference here is the firewall rules. It’s on my todo list to figure out exactly what they are doing. Below are my attempts at plain english. Given the slight differences in my setup from laroberto’s previously linked blog posts, I’m not sure if they are even necessary.
- Forwarding, accept input on
wg1
- Postrouting, as long as the destination network is not my LAN subnet, masquerade
Also, note the AllowedIPs
line on the raspberry pi peer. I’ve explicitly allowed the wg1
subnet and my LAN subnet.
# /etc/wireguard/wg1.conf
[Interface]
Address = 10.0.20.1/32
ListenPort = 51821
PrivateKey = <wg1.private.key>
PostUp = iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 ! -d 10.0.0.0/24 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg1 -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 ! -d 10.0.0.0/24 -j MASQUERADE
# raspi
[Peer]
PublicKey = <raspi.public.key>
PresharedKey = <raspi.preshared.key>
AllowedIPs = 10.0.20.0/24, 10.0.0.0/24
# laptop
[Peer]
PublicKey = <laptop.public.key>
PresharedKey = <laptop.preshared.key>
AllowedIPs = 10.0.20.11/32
# phone
[Peer]
PublicKey = <phone.public.key>
PresharedKey = <phone.preshared.key>
AllowedIPs = 10.0.20.12/32
Note
Update: make sure to add the firewall rule (
sudo ufw allow 51821/udp
). I added it on my pi, which I didn’t need to, but I did not specify to do so here initially. This is the important one, it won’t work without it if you have a firewall running on your VPS.
Additionally, make sure to uncomment the following lines to enable IPv4 and IPv6 forwarding:
# /etc/sysctl.conf
...
net.ipv4.ip_forward=1
...
net.ipv6.conf.all.forwarding=1
...
And run sudo sysctl --system
to reload.
raspberry pi
Remember this is now acting as a client instead of a server.
Info
This section was authored after the Info tag at the beginning. I will include the previous configuration, and what I changed - it is working now, seemingly.
Previous config:
# /etc/wireguard/wg1.conf
[Interface]
Address = 10.0.20.2/32
PrivateKey = <raspi.private.key>
PostUp = iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0
PostDown = iptables -D FORWARD -i wg1 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0
[Peer]
PublicKey = <vps.public.key>
PresharedKey = <vps.preshared.key>
Endpoint = <vps.public.ip>:51821
AllowedIPs = 10.0.20.0/24, 10.0.0.0/24
Note
I changed this on the fly and now can’t remember if the subnet in the configuration file was
10.0.0.0/24
or0.0.0.0/0
. I know, silly me, failing to write it down. But I believe it would fail for similar reasons either way, as0.0.0.0/0
would match all IP addresses. For the explanation below I’ve left it at10.0.0.0/24
.
I believe the AllowedIPs
line is what causes this to fail.
Throughout this process I think I wrapped my head around what the AllowedIPs
line is doing. It is telling the client what specific IPs should be redirected to the tunnel. Thus, 0.0.0.0/0
is essentially saying all traffic (matching any IP) should be routed through the VPN tunnel. Hence, when visiting any given site with that line set to match all IPs, the IP displayed matches the public IP of the VPS - the traffic from my client is getting passed to the VPS, which is then querying the website on behalf of my client.
So, with 10.0.20.0/24
and 10.0.0.0/24
listed as the two subnets to pass through the IP, any traffic destined for my home subnet is being directed through the VPN. This is okay on my other clients coming from an untrusted network, as I want those subnets to be redirected instead of being treated as local IP addresses. But on the pi itself, whose local IP is 10.0.0.2/24
, any traffic the pi tries to pass to the local network is then passed through the VPN. I’m still trying to understand exactly what would be happening here, so here is my best guess. Remember, this pi is acting as my home network DNS server.
My mini PC at 10.0.0.5
makes a DNS request, say, for google.com. This gets passed to the pi at 10.0.0.2
. The pi decides that google.com is okay (not on a blocklist), so it passes that DNS request along to 10.0.0.1
, the router acting as my upstream DNS. Now herein lies the problem. The 10.0.0.1
address matches the 10.0.0.0/24
line defined in wg1.conf
on the pi. So it tries to pass that request along through the VPN. From there, I’m not sure exactly what happens, but I bet my ass it doesn’t work.
Here’s an attempt to break down what happens and why I don’t understand exactly what’s going on:
- pi makes DNS request over port 53 to
10.0.0.1
. Gets passed throughwg1
to VPS. - VPS forwards DNS request over port 53 to
10.0.0.1
. - from VPS:
dig @10.0.0.1 google.com
returns a result, so my best guess is this specific issue is not the problem. - VPS forwards the result back to the pi, pi forwards the result back to
10.0.0.5
, which then flows through the VPS and then back to the destination. This might cause an issue, as I don’t think it would pass through my masquerade rule on the router - requesting machine might not be happy about getting a DNS response from a different machine than it requested from.
At this point, I’m not sure exactly why this line would cause the VPN to fail, but I’m leaning far more heavily towards I don’t know all the ramifications of how sending all the traffic through the VPN will impact traffic, as opposed to some bug.
Current config:
# /etc/wireguard/wg1.conf
...
[Peer]
...
AllowedIPs = 10.0.20.0/24
PersistentKeepalive = 25
Also, remember to add the firewall rule to allow connections over the new port. It seems to be a theme that I forget this kind of thing.
Note
Upon review in the morning (I did this all last night) - this rule is extraneous. It’s an outbound connection over
51821
, not inbound as before, when the pi was acting as a WireGuard server.
Client(s)
I’ve made the decision for now to stick with partial tunneling. All traffic destined for a non-local and non-wireguard IP address will go through the clearweb. This configuration has served my main purpose for the time being of giving me remote access to my LAN without opening a port on my home IP.
So with that in mind, here is the configuration for a Windows 11 machine:
[Interface]
PrivateKey = <laptop.private.key>
Address = 10.0.20.11/32
[Peer]
PublicKey = <vps.public.key>
PresharedKey = <vps.preshared.key>
AllowedIPs = 10.0.0.0/24, 10.0.20.0/24
Endpoint = <vps.public.ip>:51821
And for an Android device:
[Interface]
PrivateKey = <phone.private.key>
Address = 10.0.20.12/32
[Peer]
PublicKey = <vps.public.key>
PresharedKey = <vps.preshared.key>
AllowedIPs = 10.0.0.0/24, 10.0.20.0/24
Endpoint = <vps.public.ip>:51821
Putting the 10.0.0.0/24
and 10.0.20.0/24
subnets as the AllowedIPs
for these clients means that any traffic destined for the WireGuard subnet or my home network subnet gets passed through the VPN - as intended. All other traffic does not pass through the VPN.
Remaining to-do
- Change home LAN network to something less common, such as
10.0.10.0/24
, to avoid conflict with other LANs while VPN is enabled. - Purchase firewall and shuffle setup around to move WireGuard to that machine.
EOF