Zero-Friction Remote Access to My Home LAN via WireGuard
Turn a 3-hop SSH chain into a one-click, “as-if-you’re-home” experience.
Goal: From my laptop anywhere in the world, reach any device on my home LAN (e.g.,192.168.0.x) directly—without manual SSH hop-by-hop (Laptop → VPS → Raspberry Pi → Desktop).
Strategy: Put the laptop into the same WireGuard VPN as my VPS and Raspberry Pi, and let the Pi act as the gateway to my home LAN.
Topology (what we’re building)
- WireGuard subnet:
10.0.0.0/24- VPS (WG server):
10.0.0.1 - Raspberry Pi (WG client + home gateway):
10.0.0.7- Home LAN interface (e.g.,
eth0):192.168.0.41 - Home LAN network:
192.168.0.0/24
- Home LAN interface (e.g.,
- Laptop (WG client):
10.0.0.8
- VPS (WG server):
Once done, from the laptop I can simply:
ssh user@192.168.0.50 # my desktop at home
No more multi-jump SSH gymnastics.
Visual: packets in and out
flowchart LR
subgraph Internet
L[Laptop 10.0.0.8]
V[VPS 10.0.0.1]
end
subgraph Home
P[Raspberry Pi<br/>10.0.0.7 / 192.168.0.41]
R[Home Router 192.168.0.1]
D[Desktop 192.168.0.50]
O[Other LAN Devices 192.168.0.x]
end
L <-- WireGuard (UDP/51820) --> V
V <-- WireGuard (UDP/51820) --> P
P <-- Ethernet/Wi-Fi --> R
R <-- LAN --> D
R <-- LAN --> O
L -- 192.168.0.0/24 --> P
P -- forwards --> D
Two routing options (pick one)
- Option A — Pure routing (recommended):
Add a static route on your home router:10.0.0.0/24via192.168.0.41(the Pi).
This keeps source IPs intact and is the cleanest design.
- Option B — NAT on the Pi (no router changes):
Masquerade traffic from10.0.0.0/24to look like it originates from192.168.0.41.
Simpler if you can’t touch the router, but home devices will only “see” the Pi as the source.
Both work. I’ll show config for both.
0) Prereqs
- WireGuard installed on VPS, Pi, and Laptop.
- Port UDP/51820 open on the VPS firewall/cloud provider.
- Correct time on all machines (handshakes rely on sane clocks).
1) VPS (WireGuard server) config
File: /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
# Raspberry Pi peer (also routes home LAN)
[Peer]
PublicKey = <PI_PUBLIC_KEY>
# IMPORTANT: the server must know that 192.168.0.0/24 is behind the Pi
AllowedIPs = 10.0.0.7/32, 192.168.0.0/24
# Laptop peer
[Peer]
PublicKey = <LAPTOP_PUBLIC_KEY>
AllowedIPs = 10.0.0.8/32
Open the port (examples):
# UFW
sudo ufw allow 51820/udp
sudo ufw status
# or check socket
sudo ss -lunp | grep 51820
Bring it up:
sudo wg-quick up wg0
sudo wg show
2) Raspberry Pi (WireGuard client + LAN gateway)
WireGuard config: /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.7/32
PrivateKey = <PI_PRIVATE_KEY>
# Enable forwarding automatically when WG is up (safe & convenient)
PostUp = sysctl -w net.ipv4.ip_forward=1
PostDown = sysctl -w net.ipv4.ip_forward=0
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <VPS_PUBLIC_IP_OR_DOMAIN>:51820
# Send traffic to VPN subnet through WG
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
Apply and verify:
sudo wg-quick up wg0
sudo wg show
# Expect: latest handshake present, some bytes transferred
Option A — Pure routing (preferred)
- Permanent IP forwarding (also covered by PostUp but set globally too):
sudo sed -i 's/^#\?net.ipv4.ip_forward=.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p
- Home router static route (do this in your router UI):
Destination: 10.0.0.0/24
Next-hop : 192.168.0.41 # the Pi's LAN IP
No NAT rules are needed on the Pi for Option A.
Option B — NAT on the Pi (if you can’t change the router)
Find the Pi’s LAN interface name (usually eth0 or wlan0):
ip r | grep default # shows the interface of the default route
Use iptables NAT:
# one-time (until reboot)
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
Automate via WireGuard hooks (replace eth0 if different):
[Interface]
Address = 10.0.0.7/32
PrivateKey = <PI_PRIVATE_KEY>
PostUp = sysctl -w net.ipv4.ip_forward=1; iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <VPS_PUBLIC_IP_OR_DOMAIN>:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
nftables variant:
sudo nft add table ip nat
sudo nft 'add chain ip nat postrouting { type nat hook postrouting priority 100 ; }'
sudo nft add rule ip nat postrouting ip saddr 10.0.0.0/24 oif "eth0" masquerade
3) Laptop (WireGuard client)
File: wg0.conf on your laptop (location depends on OS; on Linux /etc/wireguard/wg0.conf, on macOS with wireguard-tools you can import; on Windows use the WireGuard app).
[Interface]
Address = 10.0.0.8/32
PrivateKey = <LAPTOP_PRIVATE_KEY>
# Optional: use the Pi or your home DNS if you want local names
# DNS = 192.168.0.1
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <VPS_PUBLIC_IP_OR_DOMAIN>:51820
# CRUCIAL: we want to reach the VPN AND the home LAN through the tunnel
AllowedIPs = 10.0.0.0/24, 192.168.0.0/24
PersistentKeepalive = 25
Bring it up and check:
sudo wg-quick up wg0 # or use the WireGuard GUI on macOS/Windows
sudo wg show
4) Test, then enjoy “as-if-you’re-home”
- Handshake check (on all three nodes):
sudo wg show # look for "latest handshake" and non-zero transfer
- From Laptop:
# Reach the Pi across WG
ping 10.0.0.7
# Reach the Pi’s LAN IP
ping 192.168.0.41
# Reach your home router & desktop
ping 192.168.0.1
ping 192.168.0.50
# SSH straight to home devices (no more manual jumps)
ssh youruser@192.168.0.50
If pings to 10.0.0.7 work but 192.168.0.x don’t:
- On Option A: your home router’s static route is missing or wrong.
- On Option B: your NAT rule may be missing or on the wrong interface.
Common pitfalls & quick fixes
- No handshake on
wg show:- Wrong keys or
Endpoint; VPS UDP/51820 not open; clock skew. - On the laptop, ensure
Endpointpoints to the VPS (public IP or domain).
- Wrong keys or
- Handshake OK, but can’t reach
192.168.0.x:- Laptop’s
AllowedIPsmust include192.168.0.0/24. - Server’s Pi peer
AllowedIPsmust include192.168.0.0/24. - On Option A: add static route on the home router to send
10.0.0.0/24→ Pi. - On Option B: verify MASQUERADE on the Pi’s LAN interface.
- Laptop’s
- UFW/nftables forwarding blocked:
- UFW:
sudo ufw default allow routedor addufw route allowrules. - nftables: ensure forward chain isn’t dropping by default.
- UFW:
- Interface name mismatch:
- Replace
eth0with your actual LAN interface (ip -br ato list).
- Replace
Hardening & quality of life
- Keys & permissions:
Store private keys withchmod 600, don’t commit to git. - Keepalives:
PersistentKeepalive = 25is your friend behind NATs. - MOSH for flaky networks:
If you do long sessions over shaky Wi-Fi, trymosh(UDP), it survives roaming.
SSH convenience:
Add this to your laptop’s ~/.ssh/config for short names:
Host homedesktop
HostName 192.168.0.50
User youruser
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30
ServerAliveCountMax 3
Now it’s just:
ssh homedesktop
Why this beats multi-hop SSH
- Fewer moving parts: no ProxyJump chains to break.
- True LAN feel: you can reach any
192.168.0.xservice (SSH, SMB, web UIs). - Easier automation: backups, dev mounts, home lab dashboards just work.
- Scale-ready: add more sites (e.g., office) by advertising their subnets via WG peers.
Copy-paste checklist
- VPS: add Pi peer (
10.0.0.7/32, 192.168.0.0/24) and Laptop peer (10.0.0.8/32); openudp/51820. - Pi: enable IPv4 forwarding;
AllowedIPs = 10.0.0.0/24; set Option A static route on router or Option B NAT on Pi. - Laptop:
AllowedIPs = 10.0.0.0/24, 192.168.0.0/24;Endpoint = VPS:51820. - All:
wg show→ handshake OK;ping→10.0.0.7,192.168.0.41,192.168.0.50. - Done:
ssh youruser@192.168.0.50from anywhere.