Budget one evening for the initial build and a hardware cost about equal to a pizza. By the end, your phone or laptop connects back to your house from any public Wi-Fi, with an encrypted tunnel, access to your NAS or Home Assistant, and an exit that’s literally your own home IP.

This guide zooms in on one project from our Raspberry Pi VPN overview, the most requested one: building a personal WireGuard server, command by command.

What this guide covers, and what it doesn’t

This builds a personal WireGuard server hosted on your Raspberry Pi, via PiVPN. That’s not the same thing as a commercial VPN like NordVPN: it doesn’t change your apparent location and it doesn’t anonymize you among other users, since the exit is your home address. In exchange, it gives you free, encrypted access to your home network from anywhere, for life, with no subscription.

Once it’s running, this setup lets you:

  1. Reach a NAS interface (Synology, QNAP, TrueNAS) from outside without exposing its web port directly to the internet.
  2. Control Home Assistant or any other home automation server from outside the local network, without routing through a third-party cloud service.
  3. Watch your Plex or Jellyfin library from a hotel or a friend’s place, appearing as a device on the home network.
  4. Remotely manage other machines on the network (printer, IP camera, another Pi) without opening their ports individually on the router.
  5. Encrypt browsing on untrusted public Wi-Fi, with an exit that’s your own router rather than a third-party server.

What it doesn’t do: it doesn’t hide your home IP, the exit node is literally your house, it doesn’t unblock foreign catalogs, and it offers no protection from your own ISP, which still sees WireGuard traffic passing through your connection. A commercial VPN and this personal server solve different problems and pair well together rather than competing.

Picking the hardware: which Pi, which card, which power supply

A Raspberry Pi 4 (2GB of RAM is enough) or a Pi 5 both work well. As a rough guide, a Pi 4 pushes WireGuard around 300 to 500 Mbps in real-world use, comfortably above most residential fiber connections. A Pi 5 often clears 700 Mbps. A Pi 3 or a Zero 2 W also work for this specific project, since a personal setup’s traffic stays modest, but they cap much lower, around 50 to 100 Mbps, which starts to matter if you plan to stream 4K video through the tunnel. If the Pi will also run Pi-hole (the last step in this guide) alongside the VPN, aim for a Pi 4 or 5 to keep some headroom.

For storage, a quality microSD card (a recognized brand, A1 or A2 rated) at 32GB is plenty. A more durable alternative: boot from a USB 3.0 stick or a small USB SSD instead, which Pi 4 and 5 support natively. It takes a bit longer to set up, but it removes the most common failure point on a Pi that runs continuously: SD card wear from repeated system log writes.

For power, use the official supply matching your model (5V/3A for the Pi 4, USB-C 5V/5A for the Pi 5) or an equivalent quality charger. An undersized power supply causes voltage drops that show up as random crashes, corrupted SD cards, and WireGuard connections that drop for no obvious reason. It’s the most underrated cause of failure in this kind of build.

Finally, prefer an Ethernet cable to the router. Wi-Fi works, but a wired link removes one source of instability for a service meant to stay up around the clock.

What you need before starting

Hardware: a Raspberry Pi 4 or 5, a microSD card of at least 16GB (32GB recommended) or a USB stick/SSD, an official power supply, an Ethernet cable, and a computer with an SD card reader for flashing.

Network access: access to your router’s admin interface, meaning the actual admin login, not just the Wi-Fi password. Ideally a public IP that doesn’t change too often. Check whether your ISP uses CGNAT (sharing one public IP across several households): if so, self-hosting won’t work from outside until you get a dedicated public IP from your provider, something most ISPs hand out free on request.

Step 1: flash Raspberry Pi OS onto the SD card

Download and install Raspberry Pi Imager from raspberrypi.com/software on your computer. Launch it and pick Raspberry Pi OS Lite (64-bit) as the operating system: the version without a desktop, which is plenty for a VPN server, lighter to run continuously, and has a smaller attack surface than a full desktop image.

Select your SD card (or USB drive) as the destination. Before clicking write, open the advanced options (the gear icon, or Ctrl+Shift+X) to pre-configure:

  • a hostname, for example pivpn
  • SSH enabled, ideally with public-key authentication rather than a password (see the security section below for generating that key)
  • your username and password
  • Wi-Fi credentials, only if you won’t be wiring in via Ethernet
  • time zone and keyboard layout

Write the image. Once done, insert the card into the Pi and boot it, wired to the router over Ethernet. Setting up SSH and networking at this stage means the rest of this guide can be done without a monitor or keyboard attached to the Pi: everything runs from your regular computer, headless.

Step 2: connect over SSH and update the system

From your computer, open a terminal (or PowerShell on Windows):

ssh pi@pivpn.local

Swap pi for your chosen username and pivpn.local for the hostname set earlier. If .local resolution doesn’t work (some routers block the mDNS protocol behind it), find the Pi’s IP address from your router’s connected-devices list and connect directly with ssh pi@192.168.1.XX.

Once connected, update the system before installing anything:

sudo apt update && sudo apt full-upgrade -y
sudo reboot

Reconnect over SSH after the reboot. This is also a good moment to check available disk space (df -h) and CPU temperature (vcgencmd measure_temp).

Step 3: give the Pi a fixed local IP

The Pi needs to keep the same local IP address, or the port forward set up later will break the first time the router reassigns addresses. Two options.

The first, recommended, is a DHCP reservation on the router. In the router’s admin interface, find the DHCP or “connected devices” section, locate the Pi by its MAC address (visible with ip link show eth0 on the Pi), and reserve it a fixed IP, say 192.168.1.50. This is the most reliable method, since it survives a full OS reinstall on the Pi.

The second, if the router doesn’t offer that option, is a static IP set directly on the Pi via sudo nmtui, a simple text interface that avoids hand-editing network config files.

Step 4: install PiVPN

PiVPN automates nearly all of the WireGuard install, key generation, and firewall setup. One command launches the interactive installer:

curl -L https://install.pivpn.io | bash

The wizard asks a series of questions. Answer as follows:

  1. VPN software choice: pick WireGuard over OpenVPN. Its codebase is far smaller, so easier to audit, its protocol is more modern, and its throughput is noticeably better on modest hardware like a Pi.
  2. Local user: confirm the auto-detected user.
  3. Static IP: PiVPN detects the current IP and asks for confirmation, which is expected if step 3 was done.
  4. Listening port: the default (51820/UDP) works for the vast majority of setups. Changing it to a random port above 10000 adds a minor layer of obscurity against automated scans, see the security section below.
  5. DNS for clients: public resolvers (Cloudflare 1.1.1.1 or Quad9 9.9.9.9) work out of the box. If Pi-hole comes later, this setting can be changed afterward without reconfiguring everything.
  6. Public address: this is where dynamic DNS matters, see the next step before confirming if your public IP changes regularly, which is the case for nearly all residential connections.
  7. Unattended upgrades: accept. This applies OS security patches automatically without manual intervention.

At the end, PiVPN offers to reboot:

sudo reboot

Step 5: set up dynamic DNS (DDNS)

Most residential connections don’t have a fixed public IP: the router’s address changes now and then, often after a power outage, a reboot, or simply after a few days or weeks depending on the provider’s policy. If the WireGuard client points at an IP that has since changed, the connection fails silently, with no clear error message.

The fix: a dynamic DNS service that maps a fixed hostname, say yourname.duckdns.org, to the current public IP, updated automatically whenever it changes.

  1. Create a free account with a DDNS provider. DuckDNS is the easiest to automate on a Raspberry Pi and is documented natively by PiVPN, but No-IP and FreeDNS are equally valid alternatives.
  2. Create a subdomain and grab your auth token.
  3. Install the auto-update script, usually a cron job that runs every five minutes and updates the DNS record if the IP has changed. DuckDNS’s documentation provides this as a single line to paste into the terminal.
  4. Confirm the update is working by checking the log file the script generates, which should read “OK” after each run.
  5. If PiVPN was already installed pointing at a raw IP rather than a hostname, regenerate client profiles with pivpn -a so they point at the correct hostname.

Step 6: open the port on your router (port forwarding)

The Pi listens on UDP port 51820 internally (or the custom port chosen in step 4), but the router blocks unsolicited inbound traffic from the internet by default. A port forwarding rule is needed, sometimes called port redirection or NAT/PAT depending on the vendor:

  1. Open the router’s admin interface, usually at an address like 192.168.1.1 or 192.168.0.1 (login often printed on the router’s label).
  2. Find the advanced networking, NAT, or port forwarding section.
  3. Create a rule: external port 51820, protocol UDP, forwarded to the Pi’s local IP set in step 3, internal port 51820.
  4. Save and, if prompted, reboot the router.

This step varies a lot by ISP and router model. If the interface described here doesn’t match what’s on screen, search “port forwarding” followed by the exact router model.

A common trap: some ISP routers run in “bridge” mode behind another box (a backup 4G/5G router, a repeater that also routes), which adds an extra layer of NAT to get through. If port forwarding alone doesn’t work, check for a second router upstream that’s also blocking traffic.

Step 7: create a client profile and connect

Back in SSH on the Pi, generate a profile for each device that will connect: phone, laptop, tablet. One profile per device, never shared, which allows revoking an individual access if a device is lost or stolen:

pivpn -a

Give it a clear name (iphone-name, work-laptop). PiVPN generates a .conf file and saves it to ~/configs/.

To get that file onto a phone, the fastest method is a QR code:

pivpn -qr

Pick the profile, and a QR code prints directly in the terminal. Open the WireGuard app (available on the App Store and Play Store), tap “+”, then “Scan from QR code”, and scan the terminal’s screen, or a screenshot of it if the terminal session is remote.

For a computer, transfer the .conf file over SCP and import it into the desktop WireGuard client:

scp pi@pivpn.local:~/configs/work-laptop.conf .

Import that file into the WireGuard app installed on the computer (Windows, macOS, Linux).

By default, PiVPN sets up a full tunnel: once connected, all of a device’s traffic, including regular web browsing, routes back through the home connection. That’s the right behavior for encrypting an untrusted public Wi-Fi session, but it uses the router’s upload bandwidth every time it’s active. To route only traffic bound for the home network and let everything else exit locally, edit the AllowedIPs line in the client’s .conf file: replace 0.0.0.0/0 with the local subnet only, for example 192.168.1.0/24.

Step 8: confirm it actually works

Don’t skip this step. Turn off the phone’s Wi-Fi, switch to mobile data to be genuinely outside the local network, activate the WireGuard profile, then:

  1. Confirm you can reach an internal service, the NAS or Home Assistant web interface, for example, via its local IP.
  2. Run an IP leak test from the device connected to the tunnel: the IP shown should be the home router’s, not the mobile carrier’s.
  3. Check latency and throughput with a quick speed test while the tunnel is active, so there’s a baseline to compare against if slowness gets reported later.

If the connection fails, here are the most common causes and how to check each one.

SymptomLikely causeHow to check
Client won’t connect at allPort not open on the routernc -zvu <public-IP> 51820 from an external network
Works on local Wi-Fi, fails on mobilePort forward misconfigured, or double NATRecheck step 6, look for an upstream router
It worked, then stopped overnightPublic IP changed, DDNS not updatednslookup yourname.duckdns.org should return the current public IP
Connected but no services reachablePi firewall or IP forwarding disabledsudo ufw status (port must be allowed), sysctl net.ipv4.ip_forward should return 1
Throughput far below the normal connectionUnderpowered Pi model (Zero, Pi 3) or Wi-Fi on the PiSwitch to Ethernet, or see the hardware section above
Profile works on one device but not anotherCorrupted or badly transferred config fileRegenerate a fresh profile with pivpn -a

Hardening the server: what not to skip

A server exposed to the internet, even through a single UDP port, is worth a few basic security steps that take minutes to set up.

Disable SSH password authentication. If it wasn’t already done in step 1, generate a key pair on your computer (ssh-keygen -t ed25519), copy the public key to the Pi (ssh-copy-id pi@pivpn.local), then set PasswordAuthentication to no in /etc/ssh/sshd_config. Restart the SSH service (sudo systemctl restart ssh). Without this, the Pi stays exposed to automated brute-force attempts on SSH if that port is ever reachable from outside.

Install fail2ban, which automatically bans IP addresses that rack up failed login attempts:

sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban

The default configuration already covers SSH effectively, with no extra tuning needed.

Change the default SSH port. Port 22 is the first one automated bots scan. Swapping it for a random port above 2000 in /etc/ssh/sshd_config cuts down the noise from automated attempts significantly, though it’s not a substitute for solid key-based authentication.

Keep the system updated automatically. PiVPN turns on unattended-upgrades by default during install. Confirm it’s active:

sudo systemctl status unattended-upgrades

Finally, keep WireGuard profiles to the strict minimum needed. Every device should have its own profile, never a shared .conf file passed between people or machines. If a device is lost or lent out, revoke the profile in question rather than keep using it out of habit.

Backing up the config before anything breaks

An SD card eventually fails, sooner or later, that’s a property of the medium, not a sign of a bad card. Backing up the config files takes two minutes and turns a card failure into a quick restore instead of a full rebuild.

sudo tar -czvf ~/backup-wireguard-$(date +%F).tar.gz /etc/wireguard ~/configs
scp pi@pivpn.local:~/backup-wireguard-*.tar.gz .

This archive holds the server keys and every client profile. Store it somewhere off the Pi (a computer, personal cloud, external drive), and repeat the process after adding or revoking a profile.

To restore onto a new SD card after a failure, reinstall Raspberry Pi OS and PiVPN as in steps 1 and 4, then replace the generated /etc/wireguard folder’s contents with the backup archive before restarting the WireGuard service.

Adding Pi-hole (optional but worth it)

Once the WireGuard server is up, adding Pi-hole takes about ten minutes and turns the tunnel into a VPN plus ad and tracker blocker for any connected device, anywhere in the world.

curl -sSL https://install.pi-hole.net | bash

Follow the wizard: pick the network interface, pick an upstream DNS (Cloudflare or Quad9 both work well). Once installed, go back into the WireGuard config and swap the DNS handed to clients for the Pi’s own local IP:

pivpn -d

Point client DNS at Pi-hole. Regenerate existing profiles if needed, and confirm from a device connected to the tunnel that the Pi-hole dashboard (at http://<Pi-local-IP>/admin) starts logging blocked queries.

Maintenance: the ongoing cost after the build

Updates: sudo apt update && sudo apt full-upgrade -y once a month is enough, since PiVPN enables automatic security updates by default.

Revoking a lost device: pivpn -r, then pick the profile to revoke, one command, worth testing once for real rather than discovering it under pressure the day a phone goes missing.

Checking active connections: pivpn -c lists profiles and their last handshake date, useful for spotting a device that was supposedly revoked but still shows activity.

Watching the DDNS: it’s the quiet component everything depends on; if remote connections stop working overnight with no other change, it’s the first suspect.

Checking disk space and SD card health: df -h occasionally, and a glance at system logs (journalctl -p err) to catch early read/write errors.

Realistic budget once the build is done: an hour or two a year, mostly covered by the checks above.

Frequently asked questions

Can I run this alongside a commercial VPN subscription? Yes, and that’s actually the most complete setup: the personal server for reaching home, a subscription like NordVPN for anything that needs a genuine location change or anonymization. Both clients run on different devices or at different times with no conflict.

Does CGNAT rule this out for good? Not necessarily. Some ISPs hand out a dedicated public IP free on request to support, similar to the logic covered in our dedicated IP guide. Failing that, a reverse-tunnel service like Tailscale or ZeroTier works around it, at the cost of depending on a third party rather than a fully self-hosted setup.

How many devices can connect at once? A Pi 4 or 5 handles a dozen simultaneous WireGuard connections without strain for typical household use. The limit tends to come from the router’s upload bandwidth before it comes from the Pi’s CPU.

What happens if the Pi goes down while I’m traveling? The tunnel simply stops working; no other device on the home network is affected, since the Pi only routes VPN traffic and isn’t in the path of the rest of the local network. One more reason to keep a current backup, so a hardware failure means a quick restore rather than a rebuild from scratch.

Want to compare all VPNs side by side? Check our full VPN comparison table with scores across 18 criteria.

Our verdict

A personal WireGuard server on a Raspberry Pi replaces a commercial VPN for exactly one job, reaching home securely, and it does that job well, for free, forever. It's not an anonymity or location-shifting project; for that, a regular subscription remains the better option. The build takes an evening and about an hour of upkeep a year afterward. It's a solid match for anyone already running a NAS or Home Assistant worth protecting, and a project to skip for anyone just looking to unblock foreign streaming.

This guide covers the full personal WireGuard build, from install through hardening and maintenance. For how this project fits alongside the other two Raspberry Pi VPN uses, a network gateway and a Pi-hole plus commercial VPN combo, see the Raspberry Pi VPN overview.