# Raspberry Pi VPN (Networking) In this lesson you'll build a personal VPN server on your Raspberry Pi using **WireGuard** — the modern standard for VPNs. It gives you a private road into your home network: when you're at school, at a friend's house, or on vacation, you can reach devices on your home Wi-Fi — the Pi, a NAS, a media server, a smart home dashboard — as if your phone were plugged into the house. As a side effect, the road is encrypted, so nobody in between can read what you're accessing. ## How it works A quick networking refresher so the steps make sense: - Devices on your home network get **local** IP addresses like `192.168.1.42`. To the internet, your whole house appears as **one** public IP address (the router's). - By default the internet can only knock on the front door — the router. To reach devices *inside* the house, we set up one exception: the Pi runs a VPN server, and the router forwards that one port to it. - A VPN creates an **encrypted tunnel** between your phone and the Pi. Inside the tunnel we use our own private addresses: the Pi is `10.100.0.1`, your phone is `10.100.0.2`. - When you connect, your phone has two identities at once: it's on your carrier's network *and* on your home network. Anything in your home range (`192.168.1.x`) travels through the tunnel into the house. ``` phone --encrypted tunnel--> Pi --home network--> NAS, Pi, media server, ... ``` **Check your own network first:** find your Pi's local IP on the Pi with `hostname -I`. This lesson assumes it looks like `192.168.1.42`, so the home range is `192.168.1.0/24`. If your router uses a different range (some use `192.168.0.x` or `10.0.0.x`), substitute yours everywhere. ## What you need - A Raspberry Pi running Raspberry Pi OS, connected to your home network (wired ethernet is best and easiest) - Your phone, with the official **WireGuard** app (iOS or Android) - Access to your router's admin page (usually `192.168.1.1` in a browser) ## Step 1 — Install WireGuard on the Pi ``` sudo apt update sudo apt install -y wireguard wireguard-tools nftables qrencode ``` (`qrencode` prints a scannable QR code; `nftables` handles the forwarding rules later.) ## Step 2 — Create the server's keys Every WireGuard device has a **private key** (a secret) and a **public key** (safe to share). Think of them like a password and a public address. The Pi gets its pair now: ``` sudo -i cd /etc/wireguard umask 077 wg genkey | tee server.key | wg pubkey > server.pub cat server.key ``` - `sudo -i` logs you in as the administrator account (root). Type `exit` at the end of each root session to go back to your normal user. - `umask 077` makes sure new files are only readable by you. - Copy the long string from `cat server.key` — you'll paste it into the config in the next step. **Never share your private key.** The public key (`server.pub`) is fine to share. ## Step 3 — Write the server config Still as root, open the config file: ``` nano /etc/wireguard/wg0.conf ``` Type this, replacing the last line with your server's private key: ``` [Interface] Address = 10.100.0.1/24, fd08:4711::1/64 ListenPort = 47111 PrivateKey = PASTE_YOUR_SERVER_PRIVATE_KEY_HERE ``` Save (`Ctrl+O`, `Enter`) and quit (`Ctrl+X`). What the lines mean: - `Address` — the Pi's address inside the tunnel (`10.100.0.1`). - `ListenPort` — the port clients connect to. `47111`, UDP. ## Step 4 — Let the Pi forward traffic To send your phone's traffic on to other devices in the house, the Pi has to be willing to pass packets through. Two things enable that: **IP forwarding** (allow packets through) and **NAT** (let tunnel devices share the Pi's internet connection — you'll want it if you ever tunnel more than just home access). First, edit `/etc/sysctl.d/99-sysctl.conf` (`nano /etc/sysctl.d/99-sysctl.conf`). Make sure these two lines exist **without** a `#` in front of them (remove the `#` if there is one): ``` net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1 ``` Save and quit, then apply: ``` sysctl --system ``` Second, open the server config again (`nano /etc/wireguard/wg0.conf`) and add these two lines inside the `[Interface]` section (paste them exactly as one line each): ``` PostUp = nft add table ip wireguard; nft add chain ip wireguard wireguard_chain {type nat hook postrouting priority srcnat\; policy accept\;}; nft add rule ip wireguard wireguard_chain counter packets 0 bytes 0 masquerade; nft add table ip6 wireguard; nft add chain ip6 wireguard wireguard_chain {type nat hook postrouting priority srcnat\; policy accept\;}; nft add rule ip6 wireguard wireguard_chain counter packets 0 bytes 0 masquerade PostDown = nft delete table ip wireguard; nft delete table ip6 wireguard ``` `PostUp`/`PostDown` are commands that run automatically when the tunnel starts and stops — here they add and remove the NAT rule. Ugly-looking, but it's copy-paste and it's what the official docs recommend. When you're done, type `exit` to leave root. ## Step 5 — Start the VPN ``` sudo systemctl enable wg-quick@wg0 sudo systemctl start wg-quick@wg0 sudo wg ``` If `sudo wg` prints an interface called `wg0` with a public key and a listening port, the server is up. `enable` makes it start automatically after every reboot, so you only ever run the `start` command after changing the config. ## Step 6 — Open a door in the router Your phone needs to reach the Pi through the internet. Two things in your router's admin page: 1. **Give the Pi a fixed local IP.** Find the current one on the Pi with `hostname -I`, then add a **DHCP reservation** in the router (binds that IP to the Pi's MAC address). If the Pi's IP ever changes, the port forward breaks. 2. **Add a port forward: UDP port `47111` → the Pi's local IP.** Also find your home's **public IP** — it's often shown on the router's front page ("WAN IP"), or open `https://ifconfig.co` on any device at home. You'll paste it into the client config next. ## Step 7 — Add your phone as a client WireGuard calls every connected device a **peer**. Back on the Pi: ``` sudo -i cd /etc/wireguard umask 077 name=phone wg genkey | tee ${name}.key | wg pubkey > ${name}.pub wg genpsk > ${name}.psk ``` That created the phone's key pair plus a **preshared key** (an extra per-device layer of encryption). Register the phone in the server config — this appends a `[Peer]` section to `wg0.conf`: ``` echo "[Peer]" >> wg0.conf echo "PublicKey = $(cat ${name}.pub)" >> wg0.conf echo "PresharedKey = $(cat ${name}.psk)" >> wg0.conf echo "AllowedIPs = 10.100.0.2/32, fd08:4711::2/128" >> wg0.conf ``` Then tell the running server about the change (this reloads the config without kicking off connected clients): ``` wg syncconf wg0 <(wg-quick strip wg0) ``` Now build the config file the phone will use: ``` echo "[Interface]" > ${name}.conf echo "Address = 10.100.0.2/32, fd08:4711::2/128" >> ${name}.conf echo "PrivateKey = $(cat ${name}.key)" >> ${name}.conf echo "" >> ${name}.conf echo "[Peer]" >> ${name}.conf echo "PublicKey = $(cat server.pub)" >> ${name}.conf echo "PresharedKey = $(cat ${name}.psk)" >> ${name}.conf echo "Endpoint = 203.0.113.10:47111" >> ${name}.conf echo "AllowedIPs = 10.100.0.0/24, fd08:4711::/64, 192.168.1.0/24" >> ${name}.conf echo "PersistentKeepalive = 25" >> ${name}.conf ``` Replace `203.0.113.10` with **your home's public IP**, and `192.168.1.0/24` with **your home range** if it's different. What the important lines do: - `AllowedIPs` decides what travels through the tunnel. Here it's the tunnel itself plus your whole home range — so home devices are reachable. Everything else (normal web browsing, apps) goes over your carrier's network directly, exactly as usual. (If you ever want *everything* tunneled — e.g. to route it through a future Pi-hole — you'd replace that line with `AllowedIPs = 0.0.0.0/0, ::/0`.) - `PersistentKeepalive = 25` — phones sit behind carriers' NAT, so this sends a small packet every 25 seconds to keep the tunnel's door open. ## Step 8 — Connect your phone Still as root, print the config as a QR code: ``` qrencode -t ansiutf8 < ${name}.conf ``` On your phone: open the WireGuard app → tap the blue **+** → scan the QR code → toggle the tunnel **on**. (If you're using the Pi over SSH from a laptop, the QR code appears in your terminal window — just scan it with the phone.) Then `exit` root. ## Step 9 — Check it works The interesting test is from **outside** the house: turn your phone's Wi-Fi off and use cellular data. 1. On the Pi, run `sudo wg`. Your phone should appear with `latest handshake: X seconds ago` and a transfer count. 2. Open your Pi's local address in your phone's browser — `http://192.168.1.42` or `http://192.168.1.42/admin` (use your Pi's own local IP). If the page loads from a school Wi-Fi network, your phone is effectively sitting in your house. 3. Try SSH: `ssh YOUR_USER@192.168.1.42` from Termux (Android) or any SSH client on iPhone. If you get a shell, remote access is fully working. ## What you can do now Rule of thumb: anywhere you would have typed a `192.168.1.x` address while at home, that same address now works from anywhere in the world. - Web interfaces: Pi-hole admin, your NAS, Home Assistant — open them in the browser. - SSH into any device in the house. - Stream from a media server or download files from a NAS. One caveat: device **names** like `raspberrypi.local` only resolve *inside* the house, so over the tunnel, use IP addresses. ## Troubleshooting - **Phone never shows a handshake:** check the port forward is UDP (not TCP) on port `47111` pointing at the Pi's current local IP; check the `Endpoint` line has your *current* public IP (it can change — call your ISP for a static one if it's changing often); check keys were copied without extra spaces. - **Can't connect from home Wi-Fi, but cellular works:** common and often unfixable — many routers can't loop a forwarded port back to devices already inside the network (no "NAT loopback"). Test with cellular data. - **Connected, but home devices are unreachable:** the `AllowedIPs` line in the client config has the wrong home range — it must match your router's subnet, the same range your Pi's IP lives in. Also make sure Step 4 (IP forwarding) is done. - **A device works at home but not over the tunnel:** use its IP address instead of its name (see the caveat above), and double-check the device is actually on your home network. ## Security notes - Anyone with your phone's config file can walk into your home network. Treat it like a password — don't screenshot it into a shared chat. - Your Pi is now reachable from the internet. Keeping a firewall enabled (for example with `ufw`) is a good next step. - Lost a device? Delete its `[Peer]` section from `wg0.conf` and run `wg syncconf wg0 <(wg-quick strip wg0)` again — its keys stop working.