How to Set Up WireGuard on Raspberry Pi
Set up a Raspberry Pi WireGuard server with client configs, UDP forwarding, DNS, and firewall rules that permit NAS access while blocking IoT.
Set up WireGuard on a Raspberry Pi by installing the package, exchanging peer keys, enabling IP forwarding, and starting wg-quick@wg0. This guide uses Raspberry Pi OS and an IPv4 split tunnel for remote NAS access, with IoT blocked. Browsing stays on the client’s existing connection.
Prepare Raspberry Pi OS and choose boot storage
Use a dedicated Raspberry Pi 4 Model B with Ethernet and an appropriate power supply. Install Raspberry Pi OS Lite with Imager and configure an account and SSH access before the first boot. The official getting-started guide covers OS installation and remote access.
For microSD boot, write the OS to the card. USB boot is an alternative on Pi 4: include USB in the EEPROM boot order, and check whether an early board needs a bootloader update. USB disks also need adequate power; a powered enclosure may be necessary. Follow the USB mass storage boot documentation for the board and drive you use. Boot storage does not determine the WireGuard addressing plan.
Optional VLAN isolation and example addresses
If the router supports VLANs, put the Pi on its own services VLAN and allow only the required management, DNS, and NAS traffic across it. Adapt interface names and addresses in the rules below. A flat LAN also works; the Pi firewall still restricts traffic entering through wg0.
The examples use Pi 192.168.10.2, NAS 192.168.10.10, and router/DNS 192.168.10.1 on 192.168.10.0/24; IoT is 192.168.20.0/24. Reserve the Pi and NAS addresses. WireGuard uses 10.6.0.0/24, with the Pi at .1 and the client at .2. Choose ranges that do not overlap either endpoint’s existing networks.
You need inbound-reachable public IPv4. WAN addresses in 100.64.0.0/10 indicate CGNAT shared space; request public IPv4 from your ISP. DDNS cannot fix CGNAT. With your own double NAT, forward through both routers. RFC 6598
Install WireGuard
On Pi, install WireGuard:
sudo apt update
sudo apt full-upgrade
sudo apt install wireguard nftables
ip -br address
Reboot after kernel updates. Substitute your Ethernet interface for eth0. Generate the server keypair:
sudo -i
install -d -m 700 /etc/wireguard
cd /etc/wireguard
umask 077
wg genkey > server.key
wg pubkey < server.key > server.pub
exit
Generate client keys locally with wg genkey/wg pubkey or WireGuard’s app. Exchange public keys only. Run sudoedit /etc/wireguard/wg0.conf:
[Interface]
Address = 10.6.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
[Peer]
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.6.0.2/32
Replace uppercase key markers. On the client, create/import:
[Interface]
Address = 10.6.0.2/32
PrivateKey = CLIENT_PRIVATE_KEY
DNS = 192.168.10.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_PUBLIC_IPV4_OR_DDNS:51820
AllowedIPs = 10.6.0.0/24, 192.168.10.0/24, 192.168.20.0/24
Replace the endpoint. The IoT route reaches the deny rule. Server AllowedIPs binds client address to key. Additional clients need unique keys and /32s. wg(8)
For idle reachability behind NAT, optionally add PersistentKeepalive = 25 under [Peer]. Keepalives
Enable IP forwarding on the Pi
The Pi must route decrypted client packets onward to the NAS. Linux documents net.ipv4.ip_forward as the switch for forwarding IPv4 packets between interfaces. Persist it in a sysctl drop-in:
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward
The last command should report 1. Forwarding alone does not grant NAS access: the firewall and return path below must also permit it. These steps configure IPv4 only. Linux IP sysctl reference
Restrict forwarded traffic to DNS and the NAS
Router: allow/DNAT WAN UDP 51820 to 192.168.10.2:51820, then deny other unsolicited inbound traffic. Keep UPnP off.
For a fresh Pi without other firewall managers, save this as /etc/nftables.conf. Each chain runs top-down: blanket accepts would shadow restrictions. input protects the Pi; forward filters transit. nftables
flush ruleset
table inet vpn {
chain input {
type filter hook input priority filter; policy drop;
ct state invalid drop
ct state established,related accept
iifname "lo" accept
meta l4proto { icmp, ipv6-icmp } accept
iifname "eth0" udp sport 67 udp dport 68 accept
iifname "eth0" udp dport 51820 accept
iifname "eth0" ip saddr 192.168.10.0/24 tcp dport 22 accept
iifname "wg0" tcp dport 22 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state invalid drop
ct state established,related accept
iifname "wg0" oifname "eth0" ip daddr 192.168.10.1 udp dport 53 accept
iifname "wg0" oifname "eth0" ip daddr 192.168.10.1 tcp dport 53 accept
iifname "wg0" oifname "eth0" ip daddr 192.168.10.10 tcp dport { 443, 445, 5201 } accept
iifname "wg0" oifname "eth0" ip daddr 192.168.10.10 ip protocol icmp accept
counter drop
}
}
table ip vpn_nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.6.0.0/24 ip daddr 192.168.10.0/24 oifname "eth0" masquerade
}
}
Masquerading provides return routing; NAS logs see the Pi’s address. Allow these services from 192.168.10.2 in the NAS firewall. NAT
Apply locally or through Home SSH:
sudo nft -c -f /etc/nftables.conf
sudo systemctl enable --now nftables
sudo systemctl reload nftables
Stop on firewall errors before starting the tunnel. Full tunneling needs additional forwarding/NAT policy. IPv6 remains outside this tunnel.
Start WireGuard and enable it at boot
Protect the completed config, then start the wg-quick systemd instance for wg0:
sudo chmod 600 /etc/wireguard/wg0.conf
sudo systemctl enable --now wg-quick@wg0
sudo systemctl status wg-quick@wg0 --no-pager
sudo wg show
The service loads /etc/wireguard/wg0.conf; enable arranges startup on later boots. If startup fails, inspect sudo journalctl -u wg-quick@wg0 -b --no-pager for config or route errors. A running interface is not proof of a handshake: activate the client and send traffic before checking wg show. wg-quick routing
DNS and discovery
The router must resolve DNS at 192.168.10.1; VPN TCP/UDP 53 permits only that resolver. Set Home/IoT DNS permissions separately. Linux clients: install resolvconf for DNS=. DNS handling
Use DNS records or IPs. Bonjour/mDNS uses link-local multicast, UDP 5353; no reflector is configured. These unicast services need no IGMP-snooping changes. RFC 6762: Multicast DNS
Verify the Pi tunnel, NAS access, and reboot persistence
Connect over cellular. On the remote Debian laptop, install dnsutils mtr-tiny iperf3:
ping -c 3 10.6.0.1
ping -c 3 192.168.10.10
dig @192.168.10.1 example.org
sudo mtr -T -P 443 -rw -c 10 192.168.10.10
ping -c 3 192.168.20.1
NAS ping/DNS should succeed; IoT ping should increment the Pi’s sudo nft list chain inet vpn forward drop counter. TCP mtr checks HTTPS reachability.
On NAS, temporarily allow TCP 5201 from Pi; run iperf3 -s. Remotely:
iperf3 -c 192.168.10.10
iperf3 -c 192.168.10.10 -R
Measure both directions. Then stop iperf3 and remove 5201 permissions. ESnet documentation
Pi: sudo wg show should show a handshake after traffic. None: check endpoint, keys, CGNAT, UDP forwarding. Handshake without NAS access: check forwarding/NAT/NAS firewall. Transfers stalling warrants MTU diagnosis.
Reboot and repeat. Keep packages updated; Tech Sentinel covers broader patch news. Revoke lost devices by deleting their peer block and restarting wg-quick@wg0.
Sources
- Raspberry Pi: Getting started
- Raspberry Pi: USB mass storage boot
- WireGuard: Installation
- WireGuard: Quick Start
- wg(8): WireGuard configuration
- wg-quick(8): Interface setup
- nft(8): nftables reference
- Linux kernel: IP Sysctl
- WireGuard: wg-quick systemd service
- systemctl(1): Start and enable services
- journalctl(1): Filter logs by unit and boot
- RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space
- RFC 6762: Multicast DNS
- ESnet: Invoking iperf3
- mtr(8): Network diagnostics
Related
WireGuard vs OpenVPN Speed Comparison: The Real Numbers
The famous 4x gap comes from a 2017 benchmark on Linux 4.6.1. Since OpenVPN's DCO module landed in Linux 6.16, the honest answer depends on your workload.
WireGuard vs Tailscale: Which One to Run
Tailscale runs on WireGuard, so the real choice is about the control plane: key distribution, NAT traversal, relays, identity, and what fails without them.
WireGuard MTU Calculator and Fragmentation Fix
Work out the right WireGuard MTU from your path MTU, understand the 60 and 80 byte overhead, measure the real ceiling, and clamp TCP MSS correctly.