Why WireGuard on a Raspberry Pi 5 Makes Sense
WireGuard has quietly become the preferred VPN protocol for people who want speed and simplicity without the bloat of OpenVPN or IPSec. It runs in the Linux kernel, uses modern cryptography by default, and requires almost no configuration compared to older solutions. The Raspberry Pi 5, with its quad-core Cortex-A76 processor and up to 8GB of RAM, handles WireGuard traffic comfortably – even at speeds that would have pushed earlier Pi hardware to its limits.
The appeal here is concrete: a self-hosted VPN server on a Pi 5 sitting at home lets you route traffic through your home network from anywhere in the world. That means accessing local devices, bypassing restrictive Wi-Fi on public networks, and keeping your traffic off third-party VPN providers who may log more than they admit. This guide walks through the full setup from a fresh Raspberry Pi OS installation to a working WireGuard server with client configuration.

Prerequisites and Initial System Setup
Before touching WireGuard, make sure your Pi 5 is running a current version of Raspberry Pi OS (64-bit Bookworm is the target here). Run sudo apt update && sudo apt upgrade -y to pull all pending patches. Your Pi should have a static local IP address – either set through your router’s DHCP reservation or configured directly in /etc/dhcpcd.conf. Without a stable local IP, your WireGuard configuration will break every time the router reassigns addresses.
You also need a way to reach your home network from outside. That means knowing your home’s public IP address and, ideally, setting up a dynamic DNS service like Duck DNS or No-IP if your ISP rotates your IP periodically. Port forwarding on your router is also required: WireGuard uses UDP, and you’ll need to forward a chosen port (the default is 51820) from your router to the Pi’s local IP. Check your router’s admin panel for the NAT or port forwarding section – every router brands this differently, but the principle is the same.
Installing WireGuard and Generating Keys
WireGuard is available directly from the Raspberry Pi OS repositories. Install it with sudo apt install wireguard -y. Once installed, move into the WireGuard configuration directory with cd /etc/wireguard and set permissions so only root can read files there: sudo chmod 700 /etc/wireguard. Key material should never be world-readable on a server.
Generate the server’s private and public key pair with a single piped command: wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key. This writes both keys to separate files. View the private key with sudo cat /etc/wireguard/server_private.key and copy it somewhere accessible – you’ll paste it into the server config in a moment. For each client device you plan to connect, run the same genkey command and store those key pairs separately. A phone and a laptop, for example, each need their own keypair.
WireGuard’s security model is based entirely on these key pairs. There are no usernames, no passwords, and no certificate authority to maintain. A client authenticates to the server by proving it holds the private key that corresponds to the public key the server has on file. If a device’s private key is compromised, you remove its public key from the server config and generate a new pair. The process takes under a minute.
A pre-shared key (PSK) adds an optional second layer of symmetric encryption on top of the public key handshake. For a home server this is optional, but for higher-security setups it’s worth adding. Generate one with wg genpsk | sudo tee /etc/wireguard/client1_psk.key.

Writing the Server Configuration File
Create the interface configuration file at /etc/wireguard/wg0.conf using sudo nano /etc/wireguard/wg0.conf. The file has two sections: the [Interface] block for the server itself and one [Peer] block per client device.
A working server configuration looks like this. Under [Interface], set Address = 10.0.0.1/24 (this is the VPN subnet address for the Pi itself), ListenPort = 51820, and PrivateKey = followed by the contents of your server_private.key file. Add two PostUp and PostDown lines to handle NAT so that VPN clients can reach the internet through the Pi: PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE and the corresponding PostDown with -D flags in place of -A. If your Pi is on Wi-Fi instead of Ethernet, replace eth0 with wlan0. Under [Peer], add the client’s public key as PublicKey = , optionally the PSK as PresharedKey = , and set AllowedIPs = 10.0.0.2/32. Each client gets a unique IP in the VPN subnet.
Enabling IP Forwarding and Starting the Service
WireGuard’s NAT rules above won’t work unless the Linux kernel is allowed to forward packets between interfaces. Enable this permanently by editing /etc/sysctl.conf and uncommenting the line net.ipv4.ip_forward=1. Apply the change immediately with sudo sysctl -p. Without this step, clients will connect to the VPN but won’t be able to reach anything beyond the Pi itself.
Start WireGuard with sudo systemctl start wg-quick@wg0 and enable it to run at boot with sudo systemctl enable wg-quick@wg0. Check that the interface is active with sudo wg show – this prints the current server state including any connected peers. If the interface doesn’t start, the most common cause is a typo in the private key field of wg0.conf. Keys must be pasted exactly with no trailing whitespace or line breaks.
For clients, the configuration mirrors the server structure. The [Interface] block uses the client’s private key, assigns the client’s VPN IP (10.0.0.2/32), and optionally sets a DNS server. The [Peer] block points to the server’s public key, the server’s public IP and port as Endpoint = your.public.ip:51820, and sets AllowedIPs = 0.0.0.0/0 to route all traffic through the tunnel. On Android and iOS, the WireGuard app can import this config directly as a QR code generated with qrencode -t ansiutf8 .

Firewall Rules and Keeping the Connection Stable
If your Pi is running ufw, you’ll need to explicitly allow WireGuard traffic: sudo ufw allow 51820/udp. Also confirm that ufw isn’t blocking forwarded packets – check /etc/default/ufw and set DEFAULT_FORWARD_POLICY=”ACCEPT”. A VPN that passes the handshake but drops forwarded traffic is one of the more confusing failure modes, and ufw’s default forward policy is the usual cause.
For clients that sit behind NAT themselves (most home and mobile connections), adding PersistentKeepalive = 25 to the client’s [Peer] block tells WireGuard to send a keepalive packet every 25 seconds. This prevents NAT tables on intermediate routers from expiring the connection during idle periods. Without it, a mobile client that goes quiet for a few minutes may find the tunnel silently dropped and need to reconnect manually. If you’re already running a self-hosted network with tools like Tailscale, WireGuard gives you the same underlying protocol with full control over the key management and routing logic rather than delegating that to a third-party coordination server.
Adding a second client later requires only three things: generate a new keypair for the device, add a new [Peer] block to wg0.conf with a unique AllowedIPs address like 10.0.0.3/32, and reload the server config with sudo systemctl restart wg-quick@wg0. The server never needs a full reboot, and existing client connections survive the reload.





