How to Set Up Wireguard on a Raspberry Pi 3

Published: 2019-11-18
Tagged: networking raspberry-pi hacking

It's simpler than I thought it would be, although I haven't yet tried to tackle the NAT issue. Two resources that will prove helpful in debugging should you encounter problems are the unofficial documentation and the ArchLinux wiki page on using Wireguard

1. Installing Wireguard on Raspbian Buster

# install dependencies
apt install raspberrypi-kernel-headers libelf-dev libmnl-dev build-essential git
# add apt key and allow apt to install unstable packages
sudo apt-key adv --keyserver --recv-keys 04EE7237B7D453EC
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' | sudo tee --append /etc/apt/preferences.d/limit-unstable
# update the apt database
apt-get update
apt-get install wireguard

2. Configuring the Server and Client

First, generate the private and public keys:

# set restricted permissions for all created files
umask 077
# generate the key pair
wg genkey | tee privatekey | wg pubkey > publickey

Create a new directory under /etc/wireguard to store the configuration and keys. I went with wg0.

Create the server configuration file:

# Note that you're copying and pasting the keys into the conf file. They key files generated earlier only store the keys and aren't actually used by wireguard.
PrivateKey = <server private key>
# Address of server in the vpn network segment
Address =
ListenPort = 51820

# Allow server to forward traffic (in/out) and enable nat masquerade
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# For every peer, add a [Peer] section with its public key and VPN IP.
PublicKey = <client public key>
# VPN network segment address of the client. Note the tight, /32 CIDR
AllowedIPs =

Setting up clients follows the same process: first generate the public and private keys, then create a configuration file:

# Client's address on vpn network segment
Address =
PrivateKey = <client private key>

PublicKey = <server public key>
# Server address on physical network segment
Endpoint =
# Here you can decide which traffic to send over the VPN. For example:
# Redirect all traffic to vpn
AllowedIPs =
# Only send traffic to a specific peer. In this case, the VPN server and one other peer
AllowedIPs =,
# Note that you can have only one "AllowedIPs" attribute!

3. Running everything

To get everything running, use wg-quick to start the server and client wireguard interfaces:

# I created the same directory structures and named the config files the same way on both client and server.
wg-quick up /etc/wireguard/wg0/wg0.conf

You can use wg show and ifconfig to see if the interface came up fine. Now, use ping and traceroute to verify that everything connects fine:

# From client, ping server:
ping -DO
64 bytes from icmp_seq=1 ttl=64 time=13.8 ms
# Server, ping client:
ping -DO
64 bytes from icmp_seq=1 ttl=64 time=11.2 ms

traceroute is useful at seeing how peers connect to each other through the server:

# traceroute from first client to second client
traceroute -n
  traceroute to (, 30 hops max, 60 byte packets
 1  4.178 ms  4.094 ms  4.024 ms
 1  6.023 ms  6.009 ms  5.980 ms

As a final tip, remember that you can use the wg CLI tool to add/remove peers dynamically. All you need then are the public/private key pair and a config file with the [Interface] block portion. Once you set up the interface with wg-quick, you can add a peer dynamically, eg. wg set wg0 peer <public key> allowed-ips (server) and wg set wg0 peer <public key> allowed-ips endpoint (client) and you're all set!


There aren't any comments here.

Add new comment

A code cave is a series of null bytes in a process's memory.

Programming, exploring, tinkering, philosophizing.

All views expressed are my own.