Raspberry Pi: WireGuard VPN with PiVPN, your own private tunnel
Set up WireGuard on a Raspberry Pi using PiVPN, configure your phone as a peer, and tunnel back to your home network from anywhere on the internet.
I needed to reach my home network from a coffee shop, a hotel, and a friend’s house. I did not want to expose individual services to the internet. A VPN is the right tool: one entry point, encrypted, my phone becomes “on the home network” wherever I am.
WireGuard is the modern VPN. It is faster than OpenVPN, simpler to configure, and the code is small enough to audit. PiVPN is a shell script that automates the install on a Raspberry Pi. Together they take about 20 minutes from “fresh Pi” to “VPN works on my phone.”
This tutorial covers the install, the public/private key pair, the phone config, the kill switch pattern, and the OpenVPN comparison.
What you need
- Raspberry Pi 3, 4, or 5 running Raspberry Pi OS (Lite is fine)
- The Pi on your home network with a known IP address (or a hostname via DDNS)
- Your router’s admin password (to forward one port)
- An iPhone or Android phone
- About 30 minutes
What a VPN does for a Pi
A VPN puts your phone “inside” your home network, even when the phone is on a coffee-shop Wi-Fi. Once connected:
- You can reach any device on the home network (the Pi, your NAS, your printer, the Home Assistant instance).
- All traffic between your phone and the Pi is encrypted.
- The phone can reach the internet through the Pi if you configure it that way (full tunnel), or only reach the home network (split tunnel).
The VPN is the right tool when:
- You want to access services at home without exposing them to the internet.
- You do not trust the network you are on (hotel, coffee shop, airport).
- You want all traffic from your phone to go through your home connection (full tunnel).
The VPN is the wrong tool when:
- You just need to expose one service to the internet (use a reverse proxy with HTTPS, or a service like Tailscale).
- You are on a corporate network that blocks VPNs.
- You need to share the tunnel with multiple devices (Tailscale’s “Tailnet” is the right tool for that).
Install WireGuard via PiVPN
PiVPN is a shell script that wraps the WireGuard install. It handles the key generation, the server config, and the user creation.
curl -L https://install.pivpn.io | bash
The script is interactive. It will ask:
- Static IP: confirm the Pi’s IP or set one.
- User: which Linux user should own the configs (usually
pior the user you set up). - WireGuard: yes.
- Port: default 51820, change if you have a port conflict.
- DNS: pick your home DNS provider (Pi-hole, AdGuard, Cloudflare, etc.).
It will also offer unattended upgrades, which I enable for the WireGuard package.
When the script finishes, the WireGuard service is running and the firewall is configured. Verify:
sudo pivpn status
You should see the WireGuard interface and a peer list (empty for now).
The public/private key pair
WireGuard uses public-key cryptography. Each peer (the Pi, your phone) has a key pair. The public key is shared, the private key is kept secret.
- The Pi has a private key in
/etc/wireguard/wg0.conf. - Your phone will have its own key pair, generated when you add it
with
pivpn add.
The keys are tied to the IP address inside the VPN. The Pi is usually
10.6.0.1, the phone is 10.6.0.2, and so on. The keys tell the
server “this IP is allowed to talk to me.”
The math is the boring part. The takeaway: do not share the private key. The public key is in the peer’s config file, and that is the one you copy to the other side.
Add a peer (your phone)
sudo pivpn add
The script asks for a name (e.g. brian-phone) and an optional
expiration. It generates a key pair, writes the config file, and
prints a QR code.
Scan the QR code with the WireGuard app on your phone. The app imports the config. Tap the toggle. You are connected.
Verify from the Pi:
sudo pivpn status
You should see your phone’s peer, with a “latest handshake” timestamp that is recent. If the timestamp is empty, the connection is not established.
The kill switch pattern
WireGuard has a “kill switch” option in the phone app: if the VPN drops, all internet traffic stops. This is the right setting for a hotel Wi-Fi, where you do not want the phone to fall back to the untrusted network.
In the WireGuard app, edit the tunnel, and enable “Always-On” and “Block connections without VPN.” That is the kill switch.
The trade-off: with the kill switch on, if the VPN server is down, your phone has no internet. For most people, that is the right trade-off. For some people, it is too aggressive. Pick one.
Routing all traffic through the Pi (full tunnel)
By default, the WireGuard config on the phone only routes traffic to the home network through the VPN. Internet traffic goes directly out from the phone (split tunnel).
For full tunnel (all internet traffic goes through the Pi), edit the phone’s config and add:
AllowedIPs = 0.0.0.0/0, ::/0
This routes everything through the VPN. The Pi then needs IP forwarding and NAT configured, which PiVPN does by default.
The full tunnel is the right setting when:
- You do not trust the network you are on (untrusted Wi-Fi).
- You want to appear to be at home (for streaming services with geo-restrictions).
The split tunnel is the right setting when:
- You want fast internet (the Pi’s upload speed is the bottleneck for full tunnel).
- The home network is not a privacy sanctuary (you do not need to hide which network you are on).
For “I just want to reach my home stuff,” split tunnel is enough.
The “WireGuard over Wi-Fi” reliability gotcha
WireGuard over Wi-Fi can be flaky if:
- The Pi is on Wi-Fi and the connection drops occasionally. The VPN is up, but the underlying network is dropping packets.
- The phone’s Wi-Fi is congested (busy coffee shop). Same problem, different side.
The fix: if possible, wire the Pi to the router with ethernet. The phone’s Wi-Fi is what it is, but the Pi’s connection to the home network should be reliable.
The other gotcha: NAT. Most home networks have the Pi behind the router’s NAT. The router needs a port forward for WireGuard (UDP 51820 by default) to the Pi. Without that port forward, the phone cannot reach the Pi from outside the home network.
Configure the port forward on the router: external UDP 51820 -> internal UDP 51820 at the Pi’s IP. The Pi should have a static IP (or a DHCP reservation) so the port forward stays valid.
WireGuard vs OpenVPN
For almost every home use case, WireGuard wins:
- Speed. WireGuard is 2-3x faster than OpenVPN at the same CPU cost.
- Config. WireGuard config is one file, OpenVPN config is many files and a CA.
- Code size. WireGuard is about 4,000 lines of code, OpenVPN is 100,000+. Smaller code is easier to audit.
- Roaming. WireGuard handles network changes (Wi-Fi to cellular) without dropping the tunnel, OpenVPN has to reconnect.
OpenVPN wins in two places:
- Corporate compatibility. Some corporate networks block UDP (which WireGuard requires) but allow TCP (which OpenVPN can do).
- Mature tooling. OpenVPN has been around longer, has more documentation, more integrations, more “how-to” articles.
For a home VPN, WireGuard is the right choice in 2026.
The security audit: where are the keys?
After you have set this up, take a minute to think about where the keys are:
- The Pi’s private key:
/etc/wireguard/wg0.confon the Pi. Root access only. - The phone’s private key: inside the WireGuard app on the phone, which is encrypted by the phone’s filesystem encryption.
- The public keys: in each side’s config file, which is the same as the other side.
The keys are on your Pi and on your phone. They are not on a server. They are not in the cloud. There is no central authority that can be subpoenaed, hacked, or compromised. This is the part of the design that makes WireGuard trustworthy.
If the phone is lost, remove its peer from the Pi:
sudo pivpn remove brian-phone
If the Pi is compromised, the keys are exposed. Reinstall the Pi and generate new keys. The phone’s config has to be updated.
What you learned
- PiVPN automates the WireGuard install on a Raspberry Pi.
- Each peer (the Pi, your phone) has a key pair. Public keys are shared, private keys are kept secret.
- A kill switch blocks internet traffic if the VPN drops.
- WireGuard beats OpenVPN on speed, config, and code size.
When something breaks
The phone cannot connect. Check the port forward on the router (UDP 51820 to the Pi). Check the Pi’s public IP address (it can change if you have a dynamic IP from your ISP, use a DDNS service like DuckDNS or No-IP).
The phone connects but cannot reach anything. The IP forwarding
or NAT is not set up. PiVPN sets this up by default; if you removed
it, the server config is in /etc/wireguard/wg0.conf.
The connection drops every few minutes. The Pi is on Wi-Fi and the link is unstable. Move the Pi to ethernet.
pivpn status shows the peer but no handshake. The keys do not
match. Re-add the peer and re-scan the QR code on the phone.
The kill switch is too aggressive. Disable “Always-On” or “Block connections without VPN” in the WireGuard app.
What to build next
- Add a second peer (laptop, another phone).
- Add split-tunnel DNS so the phone’s DNS queries go through Pi-hole at home.
- Set up DDNS so the Pi’s IP can change without breaking the phone’s config.
- Move from PiVPN to Tailscale for zero-config multi-device.
The DDNS setup is the next thing most people need. Tailscale is the modern alternative if you do not want to forward a port.