WireGuardLab
A 3D-rendered Raspberry Pi connects by glowing blue cables through a brick firewall to a router, house, and padlock.
tutorial

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.

By WireGuardLab Editorial · · 4 min read

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

  1. Raspberry Pi: Getting started
  2. Raspberry Pi: USB mass storage boot
  3. WireGuard: Installation
  4. WireGuard: Quick Start
  5. wg(8): WireGuard configuration
  6. wg-quick(8): Interface setup
  7. nft(8): nftables reference
  8. Linux kernel: IP Sysctl
  9. WireGuard: wg-quick systemd service
  10. systemctl(1): Start and enable services
  11. journalctl(1): Filter logs by unit and boot
  12. RFC 6598: IANA-Reserved IPv4 Prefix for Shared Address Space
  13. RFC 6762: Multicast DNS
  14. ESnet: Invoking iperf3
  15. mtr(8): Network diagnostics
#wireguard #raspberry-pi#home-network#firewall

Related