WireGuard Client: Raspberry Pi OS
In this tutorial, we setup a WireGuard client on a Raspberry Pi 4 running Raspbian OS Bullseye (64-bit). Before following this tutorial, you should already have a working WireGuard server running.
Setup WireGuard
Install WireGuard
Install the WireGuard packages.
After this step, man wg
and man wg-quick
will work and the wg
command gets bash completion.
$ sudo apt install wireguard
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
wireguard-tools
The following NEW packages will be installed:
wireguard wireguard-tools
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 97.1 kB of archives.
After this operation, 332 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://deb.debian.org/debian bullseye/main arm64 wireguard-tools arm64 1.0.20210223-1 [88.9 kB]
Get:2 http://deb.debian.org/debian bullseye/main arm64 wireguard all 1.0.20210223-1 [8,164 B]
Fetched 97.1 kB in 0s (678 kB/s)
Selecting previously unselected package wireguard-tools.
(Reading database ... 37611 files and directories currently installed.)
Preparing to unpack .../wireguard-tools_1.0.20210223-1_arm64.deb ...
Unpacking wireguard-tools (1.0.20210223-1) ...
Selecting previously unselected package wireguard.
Preparing to unpack .../wireguard_1.0.20210223-1_all.deb ...
Unpacking wireguard (1.0.20210223-1) ...
Setting up wireguard-tools (1.0.20210223-1) ...
wg-quick.target is a disabled or a static unit, not starting it.
Setting up wireguard (1.0.20210223-1) ...
Processing triggers for man-db (2.9.4-2) ...
Get the Server Public Key
(We’re on the server for this section.)
Print the server’s public key. We’ll need this soon.
$ sudo wg show wg0
interface: wg0
public key: 2efuG9OYmMPQpbkJ8CVxGlvQflY6p1u+o4wjcgGII0A=
private key: (hidden)
listening port: 51820
Configure the Client
(We’re back on the client for this section.)
Create Client Keys
In every client/server relationship, each peer has its own private and public keys. Create private and public keys for the WireGuard client service. Protect the private key with a file mode creation mask.
$ (umask 077 && wg genkey > wg-private.key)
$ wg pubkey < wg-private.key > wg-public.key
Print the private key, we’ll need it soon.
$ cat wg-private.key
oBkgA+KZU6mWY5p7d0PEWxnYkihBw9TmHZXEYnQkz3g=
Create the WireGuard client service config file at /etc/wireguard/wg0.conf
.
(Use a command like sudo nano /etc/wireguard/wg0.conf
.)
# define the local WireGuard interface (client)
[Interface]
# contents of file wg-private.key that was recently created
PrivateKey = oBkgA+KZU6mWY5p7d0PEWxnYkihBw9TmHZXEYnQkz3g=
# define the remote WireGuard interface (server)
[Peer]
# contents of wg-public.key on the WireGuard server
PublicKey = 2efuG9OYmMPQpbkJ8CVxGlvQflY6p1u+o4wjcgGII0A=
# the IP address of the server on the WireGuard network
AllowedIPs = 10.0.2.1/32
# public IP address and port of the WireGuard server
Endpoint = 35.36.37.38:51820
Create the WireGuard network device at /etc/network/interfaces.d/wg0
.
(Use a command like sudo nano /etc/network/interfaces.d/wg0
.)
# indicate that wg0 should be created when the system boots, and on ifup -a
auto wg0
# describe wg0 as an IPv4 interface with static address
iface wg0 inet static
# the IP address of this client on the WireGuard network
address 10.0.2.1/24
# before ifup, create the device with this ip link command
pre-up ip link add $IFACE type wireguard
# before ifup, set the WireGuard config from earlier
pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf
# after ifdown, destroy the wg0 interface
post-down ip link del $IFACE
Configure the Server
(We’re on the server for this section.)
Edit the WireGuard service config file at /etc/wireguard/wg0.conf
.
(Use a command like sudo nano /etc/wireguard/wg0.conf
.)
Add a [Peer]
section to the bottom.
# define the remote WireGuard interface (client)
[Peer]
# contents of file wg-public.key on the WireGuard client
PublicKey = IVZrsrnY/9jzgdGdOdkKonwfCs2ZcopM9xC1OizE6Wo=
# the IP address of the client on the WireGuard network
AllowedIPs = 10.0.2.2/32
Apply the server config change.
$ sudo wg syncconf wg0 /etc/wireguard/wg0.conf
Ensure that the server config change was correctly applied.
$ sudo wg show wg0
interface: wg0
public key: 2efuG9OYmMPQpbkJ8CVxGlvQflY6p1u+o4wjcgGII0A=
private key: (hidden)
listening port: 51820
peer: IVZrsrnY/9jzgdGdOdkKonwfCs2ZcopM9xC1OizE6Wo=
allowed ips: 10.0.2.2/32
Activate the Tunnel
(We’re back on the client for this section.)
Start WireGuard.
$ sudo ifup wg0
Test the Tunnel from the Client
Are packets for the WireGuard server routed via the WireGuard tunnel utun0
?
Query the routing table.
$ ip route get 10.0.2.1
10.0.2.1 dev wg0 src 10.0.2.2 uid 1000
cache
Is the WireGuard server accessible via the tunnel? Ping the server from the client.
$ ping -c 3 10.0.2.1
PING 10.0.2.1 (10.0.2.1): 56 data bytes
64 bytes from 10.0.2.1: icmp_seq=0 ttl=64 time=45.234 ms
64 bytes from 10.0.2.1: icmp_seq=1 ttl=64 time=67.192 ms
64 bytes from 10.0.2.1: icmp_seq=2 ttl=64 time=41.907 ms
--- 10.0.2.1 ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 41.907/51.444/67.192/11.218 ms
At any time, verify that the WireGuard configuration for wg0
is what you expect:
$ sudo wg show wg0
interface: wg0
public key: server-public
private key: (hidden)
listening port: server-port
At any time, verify that the wg0
network interface exists.
$ ip address show dev wg0
7: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet server-vpn-address/vpn-size brd vpn-broadcast-address scope global wg0
valid_lft forever preferred_lft forever