MC.Back to résumé ↗

Build a "Home-Exit" WireGuard VPN — With a Windows PC as the Exit

A complete, beginner-friendly tutorial for building a "home-exit" WireGuard VPN from nothing. If you follow every step in order, you will end up with a VPN where your phone and laptop — anywhere in the world — browse the internet as if they were sitting at home, with access to your home network. This version uses an always-on Windows PC as the home-exit device.

No prior WireGuard experience is assumed. Commands are copy-paste ready; placeholders in <ANGLE_BRACKETS> are the only things you change.

Contents

Part 1 — What this is and why you'd want it

A normal commercial VPN sends your traffic out through the VPN company's servers. This one sends your traffic out through your own house. That gives you things a commercial VPN can't:

The core idea

The problem: your home internet connection usually has no fixed public address, and your router blocks unsolicited inbound connections. So your devices can't just "dial home".

The solution: rent a cheap always-on cloud server with a public IP and use it as a meeting point (a "hub"). Everything connects out to the hub — including an always-on machine at home that keeps a permanent tunnel open. The hub then relays your phone/laptop traffic down that home tunnel and out to the internet.

   YOUR DEVICES (phone, laptop) ── anywhere
        │  connect out to the hub
        ▼
   ┌───────────────────────────────┐
   │  HUB — cloud VM, public IP     │  the meeting point (relay only)
   └───────────────┬───────────────┘
        │  a permanent tunnel the home PC keeps open
        ▼
   ┌───────────────────────────────┐
   │  HOME PC — always-on Windows   │  the internet "exit"
   └───────────────┬───────────────┘
        ▼
   your home internet  +  your home network

Three kinds of machine:

RoleWhat it isWhat it does
HubA cheap cloud VM with a public IP (e.g. Oracle Cloud free tier, a $5 VPS), running LinuxListens for connections. Relays traffic. Never exits to the internet itself.
Home exitAn always-on Windows PC on your home networkKeeps a permanent tunnel to the hub. Provides the internet exit.
ClientsYour phone, laptop, etc.Connect to the hub; their traffic is routed out through home.

Trade-off: a general-purpose PC isn't purpose-built to stay on 24/7 — sleep settings, Windows Update reboots, and someone shutting it down for the night will all take the whole VPN's internet-exit offline (see Part 10). If uptime matters more to you than convenience, a small dedicated always-on box is a more robust choice for this role.

How WireGuard fits in

WireGuard is the tunnel technology. Key facts you need:

The clever part: exit through home, not the hub

Most tutorials make the hub the exit (it masquerades traffic straight out to the internet from the cloud). We deliberately don't. Instead:

You'll set this up in Part 5. Everything before that is the plumbing.


Part 2 — What you need before you start

Throughout, replace these placeholders:

PlaceholderMeaningExample
<HUB_PUBLIC_IP>The hub's public IP or DNS namevpn.example.com
<HOME_SUBNET>Your home LAN in CIDR192.168.4.0/22
<HUB_WAN_IF>The hub's internet interfaceens3

Find the hub's interface name with ip -br addr — it's the one with your real IP, not lo.


Part 3 — Install WireGuard

On the hub (Linux):

bashsudo apt update
sudo apt install -y wireguard
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

On the Windows PC: download and install the official WireGuard for Windows client. It installs a tunnel service manager — you'll import a .conf file into it in Part 6, and it can run as a Windows service so it comes up automatically at boot, before any user logs in.


Part 4 — Generate the keys

Golden rule: a private key is generated on the machine that will use it, and never copied anywhere. You only ever move public keys around.

On the hub

bashumask 077
wg genkey | sudo tee /etc/wireguard/hub_private.key | wg pubkey | sudo tee /etc/wireguard/hub_public.key

On the Windows PC

The WireGuard for Windows app generates the key pair for you the moment you create a new empty tunnel (Add Tunnel → Add Empty Tunnel...) — its public key is shown right in the app window. No separate command needed.

On each client (phone, laptop)

Now collect the public keys (safe to paste anywhere):

Keep these handy for the next parts.


Part 5 — Configure the hub (the meeting point + policy routing)

Create /etc/wireguard/wg0.conf on the hub:

bashsudo nano /etc/wireguard/wg0.conf

Paste this, filling in the placeholders:

ini[Interface]
Address = 10.7.0.1/24
ListenPort = 51820
PrivateKey = <PASTE hub_private.key CONTENTS>
MTU = 1420

# Don't let wg-quick manage routes; we do it ourselves below.
Table = off

# Allow the tunnel to forward traffic.
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT

# Reach the VPN subnet and the home LAN over the tunnel.
PostUp = ip route replace 10.7.0.0/24 dev wg0; ip route replace <HOME_SUBNET> dev wg0

# THE MAGIC: a separate routing table (200) whose default route goes INTO the tunnel,
# and rules that send client traffic (laptop .10, phone .11) into that table.
# Result: client internet traffic is relayed down to the home PC, not out the hub.
PostUp = ip route replace default dev wg0 table 200; ip route replace 10.7.0.0/24 dev wg0 table 200
PostUp = ip rule add from 10.7.0.10/32 lookup 200 priority 100; ip rule add from 10.7.0.11/32 lookup 200 priority 100
PostDown = ip rule del from 10.7.0.10/32 lookup 200 priority 100 2>/dev/null || true; ip rule del from 10.7.0.11/32 lookup 200 priority 100 2>/dev/null || true

### begin homepc ###
[Peer]
PublicKey = <HOMEPC_PUB>
# The home PC is the exit: it may send from home + act as the 0.0.0.0/0 route target.
AllowedIPs = 10.7.0.2/32, <HOME_SUBNET>, 0.0.0.0/0
### end homepc ###

### begin laptop ###
[Peer]
PublicKey = <LAPTOP_PUB>
AllowedIPs = 10.7.0.10/32
### end laptop ###

### begin phone ###
[Peer]
PublicKey = <PHONE_PUB>
AllowedIPs = 10.7.0.11/32
### end phone ###

Notice there is no MASQUERADE / NAT rule here. That's on purpose — the hub relays but never exits. The ### begin/end ### comment markers make it easy to find and swap a single peer's key later without disturbing the others.

Bring it up and make it start on boot:

bashsudo systemctl enable --now wg-quick@wg0
sudo wg show wg0        # should show the interface and your peers

Open the firewall for UDP 51820 — both in your cloud provider's security list/firewall and on the host if it runs ufw:

bashsudo ufw allow 51820/udp

Part 6 — Configure the Windows PC (the home exit)

In the WireGuard for Windows app, from the empty tunnel you created in Part 4, replace its contents with:

ini[Interface]
PrivateKey = <auto-filled by the app — leave it>
Address = 10.7.0.2/24
MTU = 1420

[Peer]
PublicKey = <HUB_PUB>
Endpoint = <HUB_PUBLIC_IP>:51820
# Accept the whole VPN subnet + everything (so it can be the internet exit).
AllowedIPs = 10.7.0.0/24, 0.0.0.0/0
# Dial OUT and keep the hole punched through the home router's NAT.
PersistentKeepalive = 25

PersistentKeepalive = 25 is essential on the home side: your home router has no port forwarding, so the PC must keep the connection alive from the inside. The hub never initiates to the PC.

Name the tunnel something memorable (e.g. home-exit) and click Activate. In the app, tick "Enable this tunnel while running", or better — install it as a service so it survives reboots without anyone logging in (see Part 8).

Unlike a Linux box, Windows doesn't need a manual MASQUERADE iptables rule — the WireGuard for Windows client handles NAT'ing tunnel traffic onto your real network adapter automatically as part of bringing the tunnel up, as long as Internet Connection Sharing-equivalent routing is implied by the AllowedIPs above. Confirm it's working in Part 9.

Network-wide DNS ad-blocking is optional. Some home-exit setups also run a DNS sinkhole on the exit device, using its tunnel address as every client's DNS server. That's a separate, optional project — skip the DNS = 10.7.0.2 line in client configs below if you don't set that up, and clients will just use their own default DNS.


Part 7 — Add a client (laptop example)

7a. Tell the hub about the client's public key

The laptop peer block already exists in the hub config from Part 5. If you're adding a new client later, add a block between markers and reload without dropping anyone:

bash# on the hub — reload live, keeping existing tunnels connected:
sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)'

7b. Create the client config

On the laptop, make a file laptop-home.conf:

ini[Interface]
PrivateKey = <PASTE laptop.key CONTENTS>
Address = 10.7.0.10/24
MTU = 1420

[Peer]
PublicKey = <HUB_PUB>
Endpoint = <HUB_PUBLIC_IP>:51820
AllowedIPs = 0.0.0.0/0    # full tunnel: all traffic via home
PersistentKeepalive = 25

Import it:

7c. Phone

In the WireGuard mobile app, create a tunnel (it makes the key pair). Use the same [Peer] values (hub public key, endpoint, AllowedIPs = 0.0.0.0/0, keepalive 25), Address = 10.7.0.11/24. Then copy the app's public key into a new ### begin phone ### block on the hub and syncconf as in 7a.

Tip: for phones, the WireGuard app can generate a QR code on the machine that holds the config (qrencode -t ansiutf8 < phone.conf), and you scan it with the app. That's what QR codes are for here — importing to a phone, not to a computer.


Part 8 — Make it survive reboots

This is the part that matters most when the exit is a general-purpose PC rather than a dedicated box, since PCs sleep, reboot for updates, and get shut down.


Part 9 — Verify it works

With the client tunnel active:

bash# 1. Handshake — on the hub, the client peer shows a recent handshake + transfer:
sudo wg show wg0

# 2. Exit is HOME, not the hub. Run on the client. It MUST print your home public IP,
#    and must NOT be the hub's public IP (that would mean traffic is escaping the hub):
curl -4 ifconfig.me

# 3. Home network reachable over the tunnel:
ping <A_DEVICE_ON_YOUR_HOME_LAN>

If both pass, you're done. Toggle the tunnel from the WireGuard app or wg-quick up/down as needed.


Part 10 — Security & operational notes


Quick reference — the addressing plan

MachineVPN IPKey role
Hub (cloud)10.7.0.1relay + policy routing; no internet exit
Home PC10.7.0.2internet exit (masquerade)
Laptop10.7.0.10full-tunnel client, routed to home PC via table 200
Phone10.7.0.11full-tunnel client, routed to home PC via table 200

Ports: UDP 51820 (hub listens; home PC and clients dial out to it).
Home LAN: <HOME_SUBNET>.