Remote LAN access with WireGuard
Translations: 简体中文 (Thanks Zhen!)
(2024-09-10) Update: Remote LAN Access with Tunneled Outbound using WireGuard
In this episode, let’s go over how to set up a simple but secure tunnel (read: VPN) to your local LAN (read: homelab) using WireGuard. We’ll be going with the VPS route so we don’t have to expose any ports to the internet.
We’ll be emulating the following setup:
The Cast:
- “Router” - The machine that will serve as the gateway (inwards) to your LAN
- “Server” - The machine with a publicly accessible IP that all clients will connect to. Also known as a “Bounce Server”
- “Client” - You, trying to connect to your LAN remotely somewhere
Boring (get it?) Setup
Note: All the machines here are Ubuntu-based. Adjust the setup accordingly to your distro of choice.
“Server” and “Router”
For “Server” and “Router” perform the following:
sudo apt update && sudo apt upgrade |
Note: To persist IP Forwarding, edit /etc/sysctl.conf
with net.ipv4.ip_forward=1
For the “Server”, create /etc/wireguard/wg0.conf
with:
[Interface] |
For the “Router”, create /etc/wireguard/wg0.conf
with:
[Interface] |
Note: Replace ens18
with the appropriate interface
Enable the interface by wg-quick up wg0
and then check the status by wg show
.
At this point, we can perform a quick sanity check. On my setup, running mtr 10.0.20.1
on the “Server” yields:
Packets Pings |
“Client”
On the “Client” perform the following:
sudo apt update && sudo apt upgrade |
Then create /etc/wireguard/wg0.conf
with:
[Interface] |
Enable the interface by wg-quick up wg0
and then check the status by wg show
. We also need to update the wg0.conf
of “Server” with “Client” as a new peer.
Update “Server” with:
[Interface] |
Note: Don’t forget to restart the wg0
interface by wg-quick down wg0 && wg-quick up wg0
Now, running mtr 10.0.20.1
on the “Client” yields:
Packets Pings |
Which follows the “Client” -> “Server” -> “Router” flow that we want.
Config digging
Most of the “routing” is dictated by the [Peer] AllowedIPs
configuration. It governs what can go in and go out of the tunnel. For example, given the following setup:
Peer A
[Interface] |
Peer B
[Interface] |
If Peer A attempts to connect to (for example) 192.168.10.11
, since the address is within 192.168.10.0/24
, it will be allowed to “enter” on Peer A’s side. When it comes out of Peer B’s side, it will be dropped since it is not within 192.168.20.0/24
. It gets a bit confusing when a “netmasked” [Interface] Address
comes into play. While [Interface] Address
can also influence the “routing” (if netmasked), the “final decision” is always up to the [Peer] AllowedIPs
. For example:
Peer A
[Interface] |
If we try to connect to 192.168.10.11
, it will be “routed” to this interface because of 192.168.10.1/24
, but it will not be allowed inside the tunnel (dropped) since it is not within 192.168.20.0/24
.
To demonstrate further, using our setup:
- Update
[Peer] AllowedIPs
of “Router” fromAllowedIPs = 192.168.10.0/24
toAllowedIPs = 192.168.10.2/32
“Client” still can reach 10.0.20.1/24
albeit “Server” cannot anymore.
- Update
[Peer] AllowedIPs
of “Client” fromAllowedIPs = 10.0.20.0/24, 192.168.10.0/24
toAllowedIPs = 10.0.20.0/24
“Client” is still able to reach 10.0.20.1/24
, but mtr
does not display the IPs of the host in the chain anymore (e.g.)
Packets Pings |
The reason is that when the hosts try to “reply” to mtr
, the packets are dropped. After all, “Server” (192.168.10.1
) and “Router” (192.168.10.3
) are not within the new [Peer] AllowedIPs
range of “Client”.
Till next time!