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
    • Laptop (WG client): 10.0.0.8

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/24 via 192.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 from 10.0.0.0/24 to look like it originates from 192.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)

  1. 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
  1. 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”

  1. Handshake check (on all three nodes):
sudo wg show    # look for "latest handshake" and non-zero transfer
  1. 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 Endpoint points to the VPS (public IP or domain).
  • Handshake OK, but can’t reach 192.168.0.x:
    • Laptop’s AllowedIPs must include 192.168.0.0/24.
    • Server’s Pi peer AllowedIPs must include 192.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.
  • UFW/nftables forwarding blocked:
    • UFW: sudo ufw default allow routed or add ufw route allow rules.
    • nftables: ensure forward chain isn’t dropping by default.
  • Interface name mismatch:
    • Replace eth0 with your actual LAN interface (ip -br a to list).

Hardening & quality of life

  • Keys & permissions:
    Store private keys with chmod 600, don’t commit to git.
  • Keepalives:
    PersistentKeepalive = 25 is your friend behind NATs.
  • MOSH for flaky networks:
    If you do long sessions over shaky Wi-Fi, try mosh (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.x service (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

  1. VPS: add Pi peer (10.0.0.7/32, 192.168.0.0/24) and Laptop peer (10.0.0.8/32); open udp/51820.
  2. Pi: enable IPv4 forwarding; AllowedIPs = 10.0.0.0/24; set Option A static route on router or Option B NAT on Pi.
  3. Laptop: AllowedIPs = 10.0.0.0/24, 192.168.0.0/24; Endpoint = VPS:51820.
  4. All: wg show → handshake OK; ping10.0.0.7, 192.168.0.41, 192.168.0.50.
  5. Done: ssh youruser@192.168.0.50 from anywhere.