How to Set Up WireGuard on a Raspberry Pi

Update: This guide was written for installing WireGuard on the Raspberry Pi. I have since written a guide specific to installing WireGuard on Ubuntu:


This is a companion discussion topic for the original entry at https://engineerworkshop.com/blog/how-to-set-up-wireguard-on-a-raspberry-pi/

I’m wondering that the only possible way for one to access geo locked content is to rent a VPS hosting service & set up Wireguard on it?

Hi Van,

Glad to hear from you again. Haha, that’s a creative idea for getting around geo IP blocking. I would suggest a VPN, which might be cheaper, but the problem with most publicly available VPNs is that they are easily identified as such and so their whole IP blocks are blocked. :slight_smile:See what I did there? Pun!

So you’re right, this would make for a much more reliable, sure-fire way.

Hope all is well,
TorqueWrench

P.S. Sorry for the delayed response. Been working 12-hour command center night shifts for the past week!

1 Like

Yeah haha thanks man. That’s intense!

@TorqueWrench Hey, how you doing man. Stay safe. I like coming back to your blog every now and then to check out new posts.

1 Like

Hi Van,

Good to hear from you again. Thank you for your continued readership! Not sure if you use Feedly or not, but it’s the tool I use to keep track of new articles on the sites I follow. You might find it useful as well.

Things are going okay here. I got back from my command center, just in time for COVID-19 to really ramp up here in the US, so it’s been all hands on deck ever since. As a result, my usual full-length articles have fallen in priority, so I really appreciate you continuing to check back.

I am hoping to have a new post either later this weekend or by the start of next month at the latest.

How about you? Hope things are going well.

Stay safe,
TorqueWrench

1 Like

Hi there,

Thanks for such a wonderful tutorial! It made me go down the rabbit hole of your previous posts :smiley: .
Though surprisingly, these instructions didn’t work out for me in the beginning. I finally got it to work in the end but I don’t quite understand why it didn’t work earlier. I hope you can help me figure this out. Here is the full story:

I have a raspberry pi 4, which is connected to the router using ethernet and it also had been connected to wifi. Its wireguard config was:

andromeda:~ $ sudo cat /etc/wireguard/wg0.conf
[Interface]
Address = 10.253.3.1/24
SaveConfig = true
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 -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 38574
PrivateKey = M****

[Peer]
PublicKey = y********
AllowedIPs = 10.253.3.2/32

Its routing table looked like this:

andromeda:~ $ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.254   0.0.0.0         UG    303    0        0 wlan0
10.253.3.0      0.0.0.0         255.255.255.0   U     0      0        0 wg0
192.168.1.0     0.0.0.0         255.255.255.0   U     202    0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     303    0        0 wlan0

Now, on my client (laptop), the config was:

$ sudo cat /etc/wireguard/andromeda.conf
[Interface]
Address = 10.253.3.2/24
PrivateKey = 6****
DNS = 1.1.1.1

[Peer]
PublicKey = F****
Endpoint = <router_ip>:38574
AllowedIPs = 10.253.3.1/32

PersistentKeepalive = 25

After forwarding udp ports on the router and ufw of server, I started both wireguards:
Server

andromeda:~ $ sudo wg
interface: wg0
  public key: F****
  private key: (hidden)
  listening port: 38574

peer: y***
  endpoint: <router_ip>:37011
  allowed ips: 10.253.3.2/32
  transfer: 5.06 KiB received, 3.14 KiB sent

Client

$ sudo wg
interface: andromeda
  public key: y***
  private key: (hidden)
  listening port: 37011

peer: F***
  endpoint: <router_ip>:38574
  allowed ips: 10.253.3.1/32
  transfer: 0 B received, 2.75 KiB sent
  persistent keepalive: every 25 seconds

So, they seem to be connected. But even now, I cannot ping 10.253.3.1. It just gets stuck.

$ ping 10.253.3.1
PING 10.253.3.1 (10.253.3.1) 56(84) bytes of data.
^C
--- 10.253.3.1 ping statistics ---
22 packets transmitted, 0 received, 100% packet loss, time 21285ms

After a lot of searching, I finally tried to just bring down my wlan0 interface and set eth0 as default interface:

andromeda:~ $ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.254   0.0.0.0         UG    0      0        0 eth0
10.253.3.0      0.0.0.0         255.255.255.0   U     0      0        0 wg0
192.168.1.0     0.0.0.0         255.255.255.0   U     202    0        0 eth0

And voila! after this I was able to ping from client.

I don’t quite understand why this was happening and do I always have to do this to make it work. Any help would be greatly appreciated. Also, it’d be nice if you can point to some resources to understand iptables, routing, split tunneling, interfaces etc.

Thanks a lot!

2 Likes

I’m doing well thanks. Local stores are frozen in the lockdown—like a ghost town. Hope things will get better. I’ve bookmarked the Feedly link, appreciate it @TorqueWrench!

1 Like

Hi there,

First of all, thank you for reading. Second, thanks for writing up such a detailed report! It’s very well written and I think you’ve identified an assumption that I had made when I wrote the article (by default, on my RPis I almost always have wifi disabled):

After a lot of searching, I finally tried to just bring down my wlan0 interface and set eth0 as default interface.

I believe what’s causing your problem is this part of the Wireguard server configuration:

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 -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

With the above config, we’re setting the server’s iptables to use eth0 as the output interface (that’s what the -o eth0 argument does) but, with wlan0 as the default (shown in your first routing table), the Pi attempts to use the wlan0 instead and dies on impact.

Solution:

If you do want to use wifi (wlan0), try changing your server’s Wireguard config instead to use -o wlan0 in PostUp and PostDown and let me know how that works out for you. (Though, honestly, unless you have a reason that you need the wifi connection, I would advise leaving it disabled; especially since it looks like both connections are using the same router).

-TorqueWrench

Hi @TorqueWrench,

Yes, after changing that to wlan0 it works quite well!
Can we somehow modify it to route the traffic to the default interface? This could be useful in the case when eth0 is disconnected and wlan0 is still connected.

Also, I’m very interested in learning about subnets, routing, interfaces, vlans, virtual interfaces etc. Do you know of a guide/resource that would teach those things?
I’m specifically looking to do the following things:

  • Create a new vpn interface and route all my torrent traffic as well as some other docker container’s traffic through it
  • Understand how docker does networking and what are the different kind of interfaces like bridge etc.

Any complete guide/tutorial would be very helpful. Thanks :slight_smile:

1 Like

It would probably require some scripting to route in such a manner. If you’d like to take a first shot at it yourself, feel free to create a new post on it in the forum. If nothing else, it would make for a great learning exercise.

Unfortunately, like you, I’ve never seen any particularly great guides on those topics. There’s a reason most of those topics are on my article to-do list. :wink:

If you have any other article requests, please let me know. I am always looking for new topics/suggestions.

Thanks again for reading. Looking forward to hearing more from you in the forum!

-TorqueWrench

1 Like

Fortunately wireguard for Buster is available from Debian Backports now.

echo “deb http://httpredir.debian.org/debian buster-backports main contrib non-free” | sudo tee --append /etc/apt/sources.list.d/debian-backports.list

1 Like

This was a great tutorial, but there seems to be an error in adding the distro keys. I figured it out, but could you update the post for others?

Sure thing! Thanks for letting me know. Those commands are what I used when I first set it up a few months ago but I will double-check to make sure they’re still valid. Do you happen to remember the error you had just to make sure I’m chasing the right thing? Thanks!

Update:

I think I found the problem. Does the following look familiar after attempting to add the key with apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138?

Executing: /tmp/apt-key-gpghome.t9MmbPxY3B/gpg.1.sh --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138
gpg: key DC30D7C23CBBABEE: public key "Debian Archive Automatic Signing Key (10/buster) <ftpmaster@debian.org>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: no writable keyring found: Not found
gpg: error reading '[stdin]': General error
gpg: import from '[stdin]' failed: General error
gpg: Total number processed: 0

If so, the fix is to run the command as sudo (i.e. instead execute the following command sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 648ACFD622F3D138). I have updated the post.

If you could just confirm that this was the error you saw, I would appreciate it so I can check this off my list. Thank you for bringing this to my attention!

Sorry for the late reply.
Yep, that was it! Thank you again; really great walkthrough!

Recurver

1 Like

You can also use this generic command: wget -O - https://ftp-master.debian.org/keys/archive-key-$(lsb_release -sr).asc | sudo apt-key add -

1 Like

Hi. TorqueWrench Thank you for the great post on wireguard on Raspberry pi… really nice step by step guide! Duck

1 Like

I copied almost everything that config files shows and changed keys where needed. After reboot (few times) I still keep getting this error. I am running this setup on RPi 4B with 4G on latest RPiOS. Any guidance appreciated.

root@raspberrypi:/etc/wireguard# systemctl status wg-quick@wg0
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/lib/systemd/system/wg-quick@.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Sun 2020-06-07 11:14:41 EDT; 6min ago
Docs: man:wg-quick(8)
man:wg(8)
https://www.wireguard.com/
https://www.wireguard.com/quickstart/
https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
Process: 543 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=1/FAILURE)
Main PID: 543 (code=exited, status=1/FAILURE)

Jun 07 11:14:41 raspberrypi systemd[1]: Starting WireGuard via wg-quick(8) for wg0…
Jun 07 11:14:41 raspberrypi wg-quick[543]: [#] ip link add wg0 type wireguard
Jun 07 11:14:41 raspberrypi wg-quick[543]: RTNETLINK answers: Operation not supported
Jun 07 11:14:41 raspberrypi wg-quick[543]: Unable to access interface: Protocol not supported
Jun 07 11:14:41 raspberrypi wg-quick[543]: [#] ip link delete dev wg0
Jun 07 11:14:41 raspberrypi wg-quick[543]: Cannot find device “wg0”
Jun 07 11:14:41 raspberrypi systemd[1]: wg-quick@wg0.service: Main process exited, code=exited, status=1/FAILURE
Jun 07 11:14:41 raspberrypi systemd[1]: wg-quick@wg0.service: Failed with result ‘exit-code’.
Jun 07 11:14:41 raspberrypi systemd[1]: Failed to start WireGuard via wg-quick(8) for wg0.

For brevity here’s my wg0.conf file with keys masked
[Interface]
Address = 10.253.3.1/24
SaveConfig = true
PrivateKey =
ListenPort = 51900

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 -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey =
AllowedIPs = 10.253.3.2/32

Hi,

I almost , no every single step

but still no luck client is stuck at
Handshake did not complete after screen

any help would be appreciated.

[Interface]
Address = 10.253.3.1/24
SaveConfig = true
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 -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51900
PrivateKey = Qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

[Peer]
PublicKey = sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
AllowedIPs = 10.253.3.2/32

[Interface]
Address = 10.253.3.2/24
PrivateKey = Sxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
DNS = 1.1.1.1

[Peer]
PublicKey = exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Endpoint = rahulinux.duckdns.org:51900
AllowedIPs = 10.253.3.1/32

PersistentKeepalive = 25

pi@raspberrypi:~ $ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.0.1 0.0.0.0 UG 202 0 0 eth0
10.253.3.0 0.0.0.0 255.255.255.0 U 0 0 0 wg0
192.168.0.0 0.0.0.0 255.255.255.0 U 202 0 0 eth0

I am exhausted, please notice and reply

Hi Rahul,

I think the problem is in your client config. Try changing the client [Interface] block’s Address = 10.253.3.2/24 to Address = 10.253.3.2/32. The reason is because we want to assign the client interface a specific IP address, not a whole block of IP addresses.

Also, do you want your client to speak to the rest of the network, or only the server? I assume you want all of your traffic to be routed through your server, so change the [Peer] block of the client from AllowedIPs = 10.253.3.1/32 to AllowedIPs = 0.0.0.0/0, ::/0.

I assume you’ve set up port forwarding on your router as well, correct?

-TorqueWrench