Wireguard VPN access
When away from home, it's always nice to be able to access devices, servers, services, on my home network.
In addition to accessing my home network's resources, if I route all of my traffic through my home network, I get the added benifit of avoiding insecure wireless networks.
There have been more than a few adviseries aginst using a hotel's wireless network, at least unencrypted (see References section below for a few links).
Besides the security, and possible data manipulation, there are times when I'm in a hotel I want to access something on my home network, but don't want to punch a hole through my home firewall.
Using a Virtual Private Network (VPN) is a simple way to securly access the internet, though my home's internet connection, and keep prying eyes at bay.
The defacto standard for years was OpenVPN, but Wireguard has taken over as the new top dog, as it's more efficient and performs better.
This can be used anywhere that there is an untrusted internet connection (hotel, airport, Starbucks, etc).
Bonus is that with this setup, I have the ability to access device(s) on my home network while traveling.
Setup is pretty simple, once you've done it a time or two.
High level overview
Read this post for details, but this is the Wireguard VPN setup.
On both the client and server
-
Install Wireguard.
-
Generate private/public key pair.
-
Using the public key of the other side of the connection, configure the tunnel end point (TEP).
On the server
-
Using the client's public key, configure the server to allow connections from the client.
-
Decide on configuration option(s) to use, such as allowed IPs, DNS server settings, etc
Use client to enable Wireguard VPN connection
- Bring up both TEPs to enable the tunnel.
Example settings
In our example, both the server and the client will generate private/public key pairs:
-
Server's private key: +BfzlVJ6o1n8hRvW4nGhpbhsiyWsCKgIEja6F8alsVg=
-
Server's public key: 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
-
Client's private key: +Dq6JSGNqpGE3nqdjXqkpSOgBYEnDiS435/QbqRHQms=
-
Client's public key: Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg=
The client will use the server's public key to encrypt data to send to the server. Only the server's private key can decrypt this data.
The server will use the client's public key to encrypt data to send to the client. Only the client's private key can decrypt this data.
Only the private key that was used to generate the public key can decrypt data encrypted with the public key, which is why you never give out your private key.
-
These instructions are listed in three sections:
-
The first section is for the SERVER.
-
The second section is for the CLIENT.
-
The third section is for the SERVER, after the client is configured.
-
Server setup
Most of the configuration is done on the server side, but neither side is difficult to configure, if you follow the steps correctly.
Enable network forwarding
If we want to connect to devices other than just the Wireguard server, we need to enable IP forwarding.
-
Enable IP forwarding by editing the /etc/sysctl.conf file and uncomment the line:
net.ipv4.ip_forward=1
-
Load the new values for the current terminal session:
sudo sysctl -p net.ipv4.ip_forward = 1
Allow tunnel traffic through the Ubuntu Firewall (ufw)
-
Check the
ufw
status:sudo ufw status Status: inactive
-
If UFW is active, then configure it to allow UDP port 51820 traffic:
sudo ufw allow 51820/udp
Install Wireguard
udo apt-get update
sudo apt install wireguard -y
Generate private/public key pair
-
Use
wg
to generate the private key, then use the private key to generate the public key:wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
Note that the output of the above command is the public key of the server.
Copy this key, as we'll need it later, to configure the client.
Configure the server's tunnel interface
-
We are sending the tunnel traffic through the main interface, so to find the public network interface name:
ip -o -4 route show to default | awk '{print $5}' enp1s0
-
Using the enp1s0 from the example above, this would be the server's tunnel interface config file /etc/wireguard/wg0.conf:
[Interface] Address = 10.0.0.1/24 SaveConfig = true ListenPort = 51820 PrivateKey = +BfzlVJ6o1n8hRvW4nGhpbhsiyWsCKgIEja6F8alsVg= PostUp = ufw route allow in on wg0 out on enp1s0 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE PreDown = ufw route delete allow in on wg0 out on enp1s0 PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE
-
The
SaveConfig
line ensures that when the Wireguard interface is shut down, any changes are saved to the config file. -
If you don't use
ufw
, or it's inactive, you can skip the lines in the config file withufw
in them.
Activate the tunnel interface
-
Bring up the tunnel interface wg0:
sudo wg-quick up wg0 [#] ip link add wg0 type wireguard [#] wg setconf wg0 /dev/fd/63 [#] ip -4 address add 10.0.0.1/24 dev wg0 [#] ip link set mtu 1420 up dev wg0 [#] ufw route allow in on wg0 out on enp1s0 Rules updated Rules updated (v6) [#] iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE
-
Check the status of the tunnel interface:
sudo wg show wg0 interface: wg0 public key: 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc= private key: (hidden) listening port: 51820
-
Tunnel interface using
ifconfig
:ifconfig wg0 wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1420 inet 10.0.0.1 netmask 255.255.255.0 destination 10.0.0.1 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Client setup
Once the server is configured, we need to generate keys on the client side, and import the server's public key.
Get the server's public key
In case you forgot to write it down...
-
On the server, run one of these commands:
sudo cat /etc/wireguard/publickey 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
Or, if we want to use Wireguard's
wg
command:sudo wg show wg0 public-key 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
Install Wireguard on the client
sudo apt-get update
sudo apt-get install wireguard -y
Generate the private/public key pair on the Linux client
wg genkey | sudo tee /etc/wireguard/privatekey | wg pubkey | sudo tee /etc/wireguard/publickey
Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg=
For Ubuntu 20.04 clients, work around a resolve bug
sudo ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf
There is a bug open for Debian (see References section for link)
If you are running an version of Ubuntu before 20.04, the workaround won't work, but this can be solved by installing the openresolv
package:
sudo apt install openresolv
Configure the client's tunnel interface
-
Get the client's private key for our client config:
sudo cat /etc/wireguard/privatekey +Dq6JSGNqpGE3nqdjXqkpSOgBYEnDiS435/QbqRHQms=
-
In our example:
- Client's private key: +Dq6JSGNqpGE3nqdjXqkpSOgBYEnDiS435/QbqRHQms=
- Server's public key: 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
-
The resulting client tunnel interace config:
sudo cat /etc/wireguard/wg0.conf [Interface] PrivateKey = +Dq6JSGNqpGE3nqdjXqkpSOgBYEnDiS435/QbqRHQms= Address = 10.0.0.2/24 DNS = 192.168.1.5, 192.168.1.6 [Peer] PublicKey = 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc= AllowedIPs = 0.0.0.0/0 Endpoint = example.com:51820 PersistentKeepalive = 25
-
I used the PersistentKeepalive = 25 setting to keep the connection open when traversing any firewalls. For more information on why this is necessary, see the Wireguard - Quick Start link in the References section below.
-
If your client's default DNS configuration uses a private DNS server (not accessible from the internet), you will need to add the DNS section of the configuration. If you don't add it, the DNS request will still be sent to the private DNS server, but it will go through the tunnel, so any DNS requests will fail.
Final server setup
Once the client's keys are generated, we need to import the client's public key into the server-side setup.
On the server, add the client to allow access
-
Using the client's public key, add the client to allowed tunnel endpoints:
sudo wg set wg0 peer Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg= allowed-ips 10.0.0.2
Save the server config after adding the client
sudo wg-quick save wg0
-
After adding the client to the server with the
sudo wg set wg0 peer
and saving the configuration with thesudo wg-quick save wg0
commands, under Final server setup, the resulting wg0.conf file on the server side would look like this:[Interface] Address = 10.0.0.1/24 SaveConfig = true ListenPort = 51820 PrivateKey = +BfzlVJ6o1n8hRvW4nGhpbhsiyWsCKgIEja6F8alsVg= PostUp = ufw route allow in on wg0 out on enp1s0 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE PreDown = ufw route delete allow in on wg0 out on enp1s0 PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE [Peer] PublicKey = Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg= AllowedIPs = 10.0.0.2/32
Bring up the tunnel and verify
Now that we (hopefully) have everything configured correctly, time to bring up the Wireguard VPN tunnel
On the client, bring up the tunnel interface
sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.2/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
Note, that with the AllowedIPs = 0.0.0.0/0 in the client config, if we are accessing the Linux box via SSH, we'll get cut off, as we just told the client to send all traffic through the tunnel. We would cut off the branch we're standing on . . . I learned this the hard way . . .
Verify the tunnel on the server side
sudo wg show wg0
interface:: wg0
public key: 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
private key: (hidden)
listening port: 51820
peer: Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg=
endpoint: 51.205.110.33:50921
allowed ips: 10.0.0.2/32
latest handshake: 1 minute, 34 seconds ago
transfer: 11.65 KiB received, 600 B sent
Verify the tunnel on the client side
sudo wg show wg0
interface: wg0
public key: Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg=
private key: (hidden)
listening port: 50921
fwmark: 0xca6c
peer: 5ifRv4mFRho36V65zq3QOc/YUebQzGF6fsRccJWVSnc=
endpoint: 162.143.28.61:51820
allowed ips: 0.0.0.0/0
latest handshake: 1 minute, 4 seconds ago
transfer: 10.93 KiB received, 25.16 KiB sent
persistent keepalive: every 25 seconds
All traffic will now flow through the tunnel.
Simple test verifying DNS and ICMP
-
Send a single ICMP request from the client to google.com
ping -c1 www.google.com
-
On the server, use
tcpdump
to capture the traffic, to show it traversing the tunnel:sudo tcpdump -nni any host 10.0.0.2 or icmp or port 53 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes 12:43:35.749283 IP 10.0.0.2.42582 > 192.168.1.5.53: 18428+ [1au] A? www.google.com. (43) 12:43:35.749287 IP 192.168.1.182.42582 > 192.168.1.5.53: 18428+ [1au] A? www.google.com. (43) 12:43:35.749302 IP 10.0.0.2.59636 > 192.168.1.5.53: 40314+ [1au] AAAA? www.google.com. (43) 12:43:35.749315 IP 192.168.1.182.59636 > 192.168.1.5.53: 40314+ [1au] AAAA? www.google.com. (43) 12:43:35.749595 IP 192.168.1.5.53 > 192.168.1.182.42582: 18428 1/0/1 A 142.251.32.164 (59) 12:43:35.749617 IP 192.168.1.5.53 > 10.0.0.2.42582: 18428 1/0/1 A 142.251.32.164 (59) 12:43:35.782867 IP 192.168.1.5.53 > 192.168.1.182.59636: 40314 1/0/1 AAAA 2607:f8b0:4000:818::2004 (71) 12:43:35.782890 IP 192.168.1.5.53 > 10.0.0.2.59636: 40314 1/0/1 AAAA 2607:f8b0:4000:818::2004 (71) 12:43:35.898450 IP 10.0.0.2 > 142.251.32.164: ICMP echo request, id 7, seq 1, length 64 12:43:35.898511 IP 192.168.1.182 > 142.251.32.164: ICMP echo request, id 7, seq 1, length 64 12:43:35.925275 IP 142.251.32.164 > 192.168.1.182: ICMP echo reply, id 7, seq 1, length 64 12:43:35.925342 IP 142.251.32.164 > 10.0.0.2: ICMP echo reply, id 7, seq 1, length 64
-
In lines 4-7, we see the DNS requests (IPv4/A and IPv6/AAAA) come in through the tunnel, get NAT'd from the client's IP (10.0.0.2) to the Wireguard server's IP (192.168.1.182) and sent to the configured DNS server of 192.168.1.5.
-
Lines 9-12 are the DNS replies for google.com
-
Finally we see the ICMP request/replies in lines 14-17 traversing the tunnel.
Web browser test
Besides just accessing the internet through my home connection, I can also access my local (192.168.1.0/24) network:
From my hotel room, accessing the web interface for one of my Pihole instances:
Configuring multiple clients
-
Follow the same client instructions to generate a key pair.
-
On the server side, add the additional client(s) the same way you added the first client.
Do not use the same key pair on multiple clients. Technically this will work, but from an accountability and security standpoint . . . don't do it.
-
Example /etc/wireguard/wg0.conf server file, with multiple clients configured:
[Interface] Address = 10.0.0.1/24 SaveConfig = true ListenPort = 51820 PrivateKey = +BfzlVJ6o1n8hRvW4nGhpbhsiyWsCKgIEja6F8alsVg= PostUp = ufw route allow in on wg0 out on enp1s0 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE PreDown = ufw route delete allow in on wg0 out on enp1s0 PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o enp1s0 -j MASQUERADE [Peer] PublicKey = Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg= AllowedIPs = 10.0.0.2/32 [Peer] PublicKey = CHCvYVqTcBsb/AD/Y6wuliQ8TDFFmcQaMqxsGN6mU2M= AllowedIPs = 10.0.0.3/32
Notes
-
I would highly recommend using a port other than 51820, as most of the Wireguard documentation refers to it, so it's a semi-well known port. Anyone trying to hack your network will quickly realize port 51820 is most likely Wireguard, so use something else. Security through obscurity . . .
-
In OSX, iOS, Android, Windows, etc (GUI-based), editing the config is easy, just change the port from 51820 to the new port using the GUI.
-
On a Linux client, there is the
wg-quick
script that is used, so that will need to be edited, or it will still use port 51820.-
Using
sed
, change the port from 51820 to 51821:sed -i 's/51820/51821/g' /usr/bin/wg-quick
-
-
Either use the port forwarding feature of your router to change the port for the client traffic, keeping the default 51820 port on the server OR
-
Change the port Wireguard listens on, in the server configuration file /etc/wireguard/wg0.conf.
-
-
As with any private/public key pair, never, never, never give out your server's private key. Treat your private key as you would a highly embarrassing and compromising photo of yourself . . . . don't let anyone ever see it!
-
The client private key should be kept private by the client, but there are some situations where that wouldn't be the case, namely if you were setting up Wireguard for someone not technical, to give them access to your system/network (aka, family members).
-
To remove a client peer from the server's config, using the original example:
sudo wg set wg0 peer Ht9LnRQS33Q4mnyK7D1aN090zWku4KRrWm6hGrVnXVg= remove
sudo wg-quick save wg0
References
Wireguard - Fast, Modern, Secure VPN Tunnel https://wireguard.com/
How to Set Up WireGuard VPN on Ubuntu 20.04 https://linuxize.com/post/how-to-set-up-wireguard-vpn-on-ubuntu-20-04/
How To Set Up WireGuard on Ubuntu 20.04 https://www.digitalocean.com/community/tutorials/how-to-set-up-wireguard-on-ubuntu-20-04
Wireguard - Quick Start - NAT and Firewall Traversal Persistence https://www.wireguard.com/quickstart/#nat-and-firewall-traversal-persistence
Debian Bug report logs - #939904 - systemd should ship resolvconf symlink in some package https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=939904
Wi-Fi security: FBI warns of risks of using wireless hotel networks https://www.techrepublic.com/article/wi-fi-security-fbi-warns-of-risks-of-using-wireless-hotel-networks/
The Hotel Hackers Are Hiding in the Remote Control Curtains https://www.bloomberg.com/news/features/2019-06-26/the-hotel-hackers-are-hiding-in-the-remote-control-curtains
Federal Bureau of Investigations - A COVID 19-Driven Increase in Telework from Hotels Could Pose a Cyber Security Risk for Guests https://www.ic3.gov/Media/Y2020/PSA201006