Ditch Cloud Services: Build Your Own VPN with PiVPN & WireGuard
Learn how to set up a secure WireGuard VPN using PiVPN on a Raspberry Pi. Access your home network remotely, protect your privacy, and self-host your own VPN—without monthly fees!
Goal
I want to be able to communicate with the devices on my network using Secure Shell (SSH) while I am away from home.
Background
I am fed up with having to use so many services like iCloud, iTunes/Spotify, Netflix, etc. I want to take back ownership of my data, media, and digital security. I don’t want to rely on any kind of “ecosystem” either. These products certainly have a convenience factor to them, but the number of subscriptions needed to maintain this convenience is becoming overwhelming to me.
This year, I plan to build some at home infrastructure to begin replacing the various subscriptions I have, but because I am frequently away from home, I want to be able to continue that work on-the-go.
The first phase of my work is going to be a virtual private network (VPN) hosted on a raspberry pi. A VPN is used to virtually extend a private network to one or multiple other networks. This means that, while connected to my VPN, I will be able to access my at home private network anywhere I have internet access.
Pi-hole is an opensource library that takes the hard part out of setting up a VPN. It allows you to setup OpenVPN or Wireguard, two free opensource VPN services. I chose Wireguard because OpenVPN only allowed for two users to connect at a time in the free tier.
Now, like me, you may be wondering how a VPN works. Wireguard uses a variation of the Noise Protocol Framework. The Noise Protocol Framework, sometimes referred to as “Noise” or “Noise Framework”, is a public domain cryptographic framework designed for creating secure communication protocols based on Diffie–Hellman key exchange. Developed by Trevor Perrin, it provides a structured approach to constructing protocols that ensure confidentiality, integrity, and various authentication modes.
I am going to try to provide a high-level overview of how the connection works, but I am only familiar with this at the hobby level. There are really two phases to the connection:
- The handshake phase
- The transport phase
In the handshake phase the initiator (the device connected to the VPN) and the responder (the raspberry pi) need to establish a secure tunnel. The initiator first provides an ephemeral key and pre-shared static key. The responder generates its own ephemeral key and pre-shared static key. The ephemeral keys are used to create a temporary connection. With that connection, the pre-shared keys are checked to match. This match is done using a Diffie-Hellman key exchange.
In the transport phase an encryption key is derived using the various keys generated in the handshake phase. Now, when the initiator does something like a google search, that request information is encrypted using the derived encryption key. The request is received by the responder and decrypted. The responder would then send the request to google and encrypted using the derived encryption key. The request is received by the responder and decrypted. The responder would then send the request to google and encrypt whatever it gets in the same way. The initiator decrypts what the responder sends in the same way. Viola! A secure extension of a private network.
Steps
Well, it is one thing to understand how it works, but how would this be implemented? Luckily, PiVPN makes it very easy to setup.
Pre-Setup
There are some pre-setup steps to do. The biggest thing is that the IP address allocated to the raspberry pi changes every time the device turns on and off. Setting a static IP address will solve this.
- For OS Bullseye and Bookworm the network configuration file is at -
sudo nano /etc/dhcpcd.conf
Scroll to the bottom and add this configuration
interface eth0 static ip_address=192.168.1.150/24 # Change this to your desired static IP
static routers=192.168.1.1 # Your router's IP (gateway)
static domain_name_servers=8.8.8.8 1.1.1.1 # Google & Cloudflare DNS
Replace eth0 with wlan0 if using Wi-Fi.
Make sure static ip_address is outside your router’s DHCP range (check your router settings).
Use your router’s IP for static routers.
Reboot
After reboot check if it worked
ip addr show eth0
Install PiVPN
curl -Lhttps://install.pivpn.io| bash
You will be prompted to answer the following
- Choose “WireGuard” when prompted.
- Set your VPN’s IP - Use your network’s public IP
- Set VPN’s DNS server - 8.8.8.8 - This is Google’s
- Keep the default port (51820/udp)
The installer will configure WireGuard and iptables automatically.
Since WireGuard listens on 51820/udp, you must forward this port on your router
Configure Wireguard
Now that WireGuard is installed, you need to add VPN clients.
- Run PiVPN’s client setup - Pivpn –a
- Enter a client name
- A WireGuard configuration file will be generated at -
/home/pi/configs/<client>.conf - Download the Wireguard app on your device - If on mobile use the following to generate qr for the app: -
pivpn -qr - If on desktop use: -
scp pi@<raspberry_pi_ip>:/home/pi/configs/<client>.conf destination - Destination based on OS - Linux:
/etc/wireguard/ - Mac:
~/Library/Application\ Support/WireGuard/ - Windows:
C:\Users\<your-username>\AppData\Local\WireGuard - On Linux, set permissions: -
sudo chmod 600 /etc/wireguard/<client>.conf - On Mac/Windows open the WireGuard app → Click Import Tunnel → Select the .conf file.
- Start - Linux/Mac: -
wg-quick up <client> - Windows Click Activate in the WireGuard app.