REM Check
Holds up
- Evidence review earlier method
- 82
- Mainstream narrative
- Review pending
- Reader agreement
Updated November 4, 2026: corrected the firewall, AllowedIPs, NAT, IP forwarding, update and QR code guidance, and added notes on PiVPN’s status and what a home VPN can’t do.
This guide shows you how to turn a Raspberry Pi into a secure home VPN server. It draws on our own journey building a VPN for a Verizon Fios network using a Pi 4 and a custom domain (vpn.insomnyak.com) with dynamic DNS. The emphasis is on open‑source tools, practical troubleshooting and security best practices. References from vendor documentation and security blogs support the recommendations.
Why Run Your Own Home VPN?
Setting up a private VPN gives you control over who can access your network and how your data is routed. A VPN encrypts traffic between your device and your home, so the network you’re on, such as hotel or café Wi‑Fi, can’t read it, and it lets you access your network from anywhere. In other words, a DIY VPN protects your browsing on untrusted networks and gives you remote access to computers or media servers on your LAN, all without paying monthly fees.
It helps to know its limits. Your traffic still leaves through your home connection, so your home ISP can see where it’s going, and a VPN doesn’t stop tracking through cookies or browser fingerprinting. It also makes you appear to be at home, so it only helps with content that’s available there.
Pros and Cons of Hosting Your Own VPN
| Pros | Cons |
|---|---|
| Control & privacy – You control the server, keys and logs, so no commercial VPN provider sits between you and your traffic. | Maintenance – You are responsible for updates, security patches and troubleshooting. |
| Remote access to your LAN – Your own VPN acts like a “secret tunnel” into your home network. It’s ideal for file shares, NAS devices or home automation dashboards. | Exposure if misconfigured – A misconfigured port forward or firewall rule can expose your Pi and network to the internet. |
| Customization – You can assign static IPs, create multiple users and combine with Pi‑hole for ad‑blocking. | ISP limitations – Dynamic DNS handles an ISP that changes your public IP, but not one that blocks inbound connections. With carrier‑grade NAT (CGNAT) port forwarding won’t work, so you’d need a public IP from your ISP or a relay service. |
| Cost‑effective – A Raspberry Pi 4 plus an SD card is inexpensive and consumes little power, and the software (WireGuard/PiVPN) is open source. | Learning curve – You need to understand networking concepts like IP addressing, NAT and DNS. |
Requirements & Preparation
Hardware & Network
Raspberry Pi 4 (4 GB RAM or higher) with a fresh 64‑bit Raspberry Pi OS installed on a 128 GB SD card.
Verizon Fios Home Router (or any router with port‑forwarding capabilities).
A domain name and dynamic DNS service. In our build we used a sub‑domain (
vpn.insomnyak.com) pointing to our public IP. Dynamic DNS keeps this host record updated if your ISP changes your IP.Stable internet connection and a computer (macOS/Windows/Linux) for SSH access.
Software
WireGuard – modern, fast VPN protocol.
PiVPN – an installer and manager for WireGuard/OpenVPN on Raspberry Pi. Its project page says it’s maintained on a best‑effort basis, so check its status before you rely on it. WireGuard itself is built into the Linux kernel and doesn’t depend on PiVPN.
Optional: Pi‑hole for DNS filtering and ad‑blocking (covered later).
Before you start
Flash Raspberry Pi OS and configure it headless. Use the Customisation tab in Raspberry Pi Imager to set a hostname, user/password, Wi‑Fi credentials (if using Wi‑Fi), locale and enable SSH. Make sure to assign a static IP (or a DHCP reservation) so the Pi’s address doesn’t change when you reboot.
Reserve an IP on your router for the Pi (e.g.,
192.168.1.210), and note your router’s admin credentials.Set up a dynamic DNS record for your domain. You will point it to your public IP and update it automatically. Many registrars provide DDNS APIs; you can also use services like DuckDNS or Cloudflare.
Open UDP port 51820 on your router and forward it to the Pi’s internal IP. PiVPN uses this port by default. Later, if you change the Pi’s interface (e.g., switch from Wi‑Fi to Ethernet), update the port‑forward rule accordingly.
Step‑by‑Step Setup Using PiVPN
PiVPN wraps the complexity of WireGuard into a friendly CLI wizard. The core steps below come from our own build.
Choose Your Firewall First
PiVPN sets up firewall rules differently depending on whether UFW is active when you run the installer, so decide now:
UFW off – PiVPN installs
iptables-persistentand saves its rules for you, so there’s nothing else to do. If you add your own iptables rules later, keep them withsudo netfilter-persistent save.UFW on – install and enable UFW before you run the installer. Allow SSH first so you don’t lock yourself out of a headless Pi:
sudo apt install ufw -y sudo ufw allow OpenSSH sudo ufw enablePiVPN then adds its own rules during the install.
Don’t turn UFW on after installing PiVPN. UFW blocks forwarded traffic by default, so clients may still connect but lose internet, LAN and Pi‑hole access. If you’ve already installed PiVPN and want UFW, set UFW up and then reinstall PiVPN.
Reinstalling creates new server keys and removes your client profiles, so every device needs a new profile afterward. Run pivpn -bk first to keep a backup.
1 Install PiVPN
SSH into the Pi using the reserved IP:
ssh pi@192.168.1.210Then run the one‑line installer:
curl -L https://install.pivpn.io | bashDuring installation you will be prompted for:
Network interface – choose
eth0orwlan0depending on how the Pi is connected. Our final setup usedeth0.Local user – select the user that will administer PiVPN (usually
pi).VPN type – choose WireGuard.
Server port – use the default
51820unless you need a different port. Remember to forward this in your router.Public DNS name – select “DNS entry” and enter your dynamic DNS host (
vpn.insomnyak.com). This lets clients connect using your domain name even if the IP changes.Upstream DNS provider – PiVPN will ask for DNS servers; you can enter
1.1.1.1and9.9.9.9. If Pi‑hole is already installed, PiVPN detects it and offers to use it instead.IPv6 leak – if your Pi has no working IPv6, PiVPN asks whether to force IPv6 through the tunnel. Answer yes, or a client’s real IPv6 address can bypass the VPN.
When the installer finishes, it will configure WireGuard, enable IP forwarding and set up basic firewall rules for you.
2 Generate a Client Profile
Use PiVPN’s CLI to add a new VPN client:
pivpn addGive the profile a descriptive name (e.g., macbook or iphone). PiVPN generates a configuration file under /home/pi/configs/. To show a QR code for a phone, run pivpn -qr.
To fetch the config on your Mac:
scp pi@192.168.1.210:/home/pi/configs/macbook.conf .Open the WireGuard app (available for macOS, Windows, iOS and Android) and import the .conf file or scan the QR code. The config will look like this:
[Interface]
PrivateKey = <client_private_key>
Address = 10.120.130.2/24
DNS = 1.1.1.1, 9.9.9.9
[Peer]
PublicKey = <server_public_key>
PresharedKey = <preshared_key>
Endpoint = vpn.insomnyak.com:51820
AllowedIPs = 0.0.0.0/0, ::/0The AllowedIPs directive routes all IPv4 and IPv6 traffic (0.0.0.0/0 and ::/0) through the VPN, and that already includes your home LAN. You only need to list the LAN subnet if you switch to a split tunnel, where just your home traffic uses the VPN (e.g., AllowedIPs = 10.120.130.0/24, 192.168.1.0/24).
3 Test the Connection
- Deactivate Wi‑Fi on your laptop or phone and connect via mobile data or a different network.
- Activate the WireGuard profile. In the WireGuard app you should see a green indicator.
From your client, check your public IP:
curl ifconfig.me
If the VPN is routing properly, this command returns your home’s public IP rather than your mobile ISP’s address. You should also be able to ping and ssh to the Raspberry Pi and other devices on your LAN.
If you cannot reach LAN devices, verify that IP forwarding and NAT are working on the server:
Check that IP forwarding is on:
sysctl net.ipv4.ip_forwardshould return1. PiVPN sets this in/etc/sysctl.d/99-pivpn.conf. If you set it by hand, use a file in/etc/sysctl.d/and load it withsudo sysctl --system, because Debian 13, the base of current Raspberry Pi OS, no longer reads/etc/sysctl.confat boot.Confirm that NAT is in place. PiVPN doesn’t add
PostUplines to/etc/wireguard/wg0.conf. It sets NAT directly in iptables, or in UFW’sbefore.rulesif UFW is active, so runsudo iptables -t nat -Sand look for aMASQUERADErule with your VPN subnet. If you run WireGuard without PiVPN, the Pi‑hole guide shows how to add one with aPostUprule.If you change the Pi’s network interface (e.g., switch from Wi‑Fi to Ethernet), update your router’s port‑forwarding rule. Our testing found that forgetting to update the port‑forward after deactivating Wi‑Fi prevented connections; once the rule pointed to the new IP the VPN worked again. PiVPN also ties its NAT rule to the interface you picked during install. If you switch interfaces, the PiVPN FAQ says the easiest fix is to reinstall and pick the new one, which means a new profile for every device (see “Choose Your Firewall First”).
Hardening & Best Practices
WireGuard’s security depends on how you configure and maintain it. We recommend the following best practices:
Keep software up‑to‑date – regularly run
sudo apt update && sudo apt full-upgrade, the command Raspberry Pi recommends. It updates the whole system, including the Linux kernel that contains WireGuard, and a new kernel only takes effect after a reboot. When the PiVPN installer offers unattended‑upgrades, say yes so Debian security fixes install automatically. Keep running the command above as well, because you shouldn’t count on this for Raspberry Pi kernel updates.Use strong unique keys – generate keys with
wg genkeyand never reuse private keys between peers. Secure the config with strict permissions (chmod 600 /etc/wireguard/wg0.conf).Keep each client to its own address – on the server,
AllowedIPslists the addresses that belong to a peer, so give each one a single tunnel address (PiVPN does this for you). It doesn’t limit what a client can reach. To do that, add firewall rules to theFORWARDchain. For example, with UFW off, these rules keep one client off your LAN except for a single device (replace the addresses with your own):sudo iptables -I FORWARD -i wg0 -s 10.120.130.3 -d 192.168.1.0/24 -j DROP sudo iptables -I FORWARD -i wg0 -s 10.120.130.3 -d 192.168.1.50 -j ACCEPT sudo iptables -I INPUT -i wg0 -s 10.120.130.3 -p tcp --dport 22 -j DROP sudo netfilter-persistent saveFORWARDrules only cover traffic passing through the Pi, so the third rule is what stops that client from using SSH on the Pi itself. Any other service on the Pi needs its ownINPUTrule.Tune PersistentKeepalive – only enable keepalive when a peer is behind NAT; set it to a reasonable interval (e.g., 25 s) to maintain the connection without excessive traffic.
Restrict firewall – forward only UDP 51820 on your router, so nothing else on the Pi is reachable from the internet. PiVPN doesn’t block other inbound traffic on the Pi itself, so use UFW if you want it filtered there too (see “Choose Your Firewall First”). WireGuard doesn’t respond to unauthorized clients, so there are no failed VPN logins to monitor; watch your SSH logs instead.
Consider a kill‑switch – on a Linux client, use a firewall rule rather than a script that reacts after the tunnel drops, so traffic can’t leak in the gap. The
wg-quickmanual includes an example. It’s a client setting, so don’t add it on the Pi.
Additional security tips for a home server include:
Disable password logins for SSH and use public‑key authentication.
Limit inbound traffic to the WireGuard port and SSH from your LAN. If you use UFW, set it up before installing PiVPN (see “Choose Your Firewall First”).
Rotate keys periodically and remove unused clients (
pivpn remove).Protect SSH with Fail2Ban to ban repeated login attempts. It only helps with SSH, because WireGuard doesn’t respond to unauthorized clients.
Enhancements & Optional Tools
Dynamic DNS Update Script
If your registrar supports an API, you can automate updating the vpn.insomnyak.com record when your public IP changes. Below is a sample Bash script for Cloudflare (replace placeholders):
#!/bin/bash
# Requirements: curl, jq
API_TOKEN="<CLOUDFLARE_API_TOKEN>"
ZONE_ID="<ZONE_ID>"
RECORD_NAME="vpn.insomnyak.com"
# Get current public IP
CURRENT_IP=$(curl -s https://api.ipify.org)
# Get existing record ID and IP from Cloudflare
RECORD_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$RECORD_NAME" -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" | jq -r '.result[0].id')
EXISTING_IP=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" -H "Authorization: Bearer $API_TOKEN" | jq -r '.result.content')
if [ "$CURRENT_IP" != "$EXISTING_IP" ]; then
echo "Updating DNS record to $CURRENT_IP"
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" --data '{"type":"A","name":"'$RECORD_NAME'","content":"'$CURRENT_IP'","ttl":120,"proxied":false}'
else
echo "IP has not changed ($CURRENT_IP)"
fi
Add this script to /usr/local/bin/update-ddns.sh. It holds your API token in plain text, so let only root read it: sudo chown root:root /usr/local/bin/update-ddns.sh && sudo chmod 700 /usr/local/bin/update-ddns.sh. Create the token with Cloudflare’s Edit zone DNS template and limit it to this one zone. Then add this line to root’s crontab (sudo crontab -e) to check every two hours and log the output so you can spot failures: 0 */2 * * * /usr/local/bin/update-ddns.sh >>/var/log/update-ddns.log 2>&1.
Combining with Pi‑hole
Running Pi‑hole on the same Pi adds network‑wide ad‑blocking and can filter adult sites. When using Pi‑hole with WireGuard, set the Pi’s tunnel address as the DNS server in the client configuration (e.g., DNS = 10.120.130.1). Install Pi‑hole before PiVPN if you can, because PiVPN then configures it for you. Adding it later takes extra setup. With UFW on, also allow ports 53 (TCP and UDP), 80 and 443, or devices on your LAN can’t reach Pi‑hole. The Pi-hole docs show how to enable IP forwarding, NAT and configure clients to access local devices. You can add blocklists or use family‑friendly DNS providers to block adult content.
Other Use Cases
Remote desktop – securely access your home PC or NAS using VNC/RDP over the VPN.
Self‑hosted services – host a media server (Plex/Jellyfin), Nextcloud or Home Assistant and reach them remotely via the VPN instead of exposing them to the internet.
Site‑to‑site connections – connect multiple homes or offices by setting up additional peers and routing between subnets.
Conclusion
Building a home VPN on a Raspberry Pi using WireGuard and PiVPN offers privacy, security and convenience. It lets you access your LAN from anywhere, encrypts your traffic over public Wi‑Fi and avoids monthly VPN fees. One caveat on untrusted networks: the TunnelVision attack (CVE‑2024‑3661) can steer traffic outside the tunnel on Windows, macOS, iOS and Linux, and a kill switch that only watches the tunnel’s status won’t catch it. The process requires some networking knowledge, but with dynamic DNS, port forwarding and PiVPN’s automation, setup is manageable. Remember to keep your system updated, use strong keys, restrict firewall rules and monitor your logs. Consider combining your VPN with Pi‑hole for ad‑blocking and dynamic DNS scripts to keep your domain updated. With these steps you’ll have a reliable, secure gateway into your home network.
What's your verdict?
You've seen the report. Your vote shapes its Reader Agreement score.