Set Up Your Own WireGuard VPN Server on Ubuntu
This tutorial is going to show you how to set up your own WireGuard VPN server on Ubuntu. WireGuard is made specifically for the Linux kernel. It runs inside the Linux kernel and allows you to create fast, modern, and secure VPN tunnel.
Features of WireGuard VPN
- Lightweight and super fast speed, blowing OpenVPN out of the water.
- Cross-platform. WireGuard can run on Linux, BSD, macOS, Windows, Android, iOS, and OpenWRT.
- User authentication is done by exchanging public keys, similar to SSH keys.
- It assigns static tunnel IP addresses to VPN clients. Some folks may not like it, but it can be useful in some cases.
- Mobile devices can switch between Wi-Fi and mobile network seamlessly without dropping any connectivity.
- It aims to replace OpenVPN and IPSec in most use cases.
Prerequisites
This tutorial assumes that the VPN server and VPN client are both running Ubuntu operating system.
Step 1: Install WireGuard on Ubuntu Server and Desktop
Log into your Ubuntu server, then run the following commands to install WireGuard.
Ubuntu 20.04
Ubuntu 20.04 ships with Linux kernel 5.4, which has a built-in wireguard module.
sudo apt update sudo apt install wireguard wireguard-tools
Ubuntu 18.04
Ubuntu 18.04 ships with Linux kernel 4.15, so users needs to install the hardware-enablement kernel first (HWE), which will install kernel 5.4 on your system.
sudo apt update sudo apt install linux-generic-hwe-18.04-edge
Restart your Ubuntu 18.04 server and install WireGuard.
sudo shutdown -r now sudo apt install wireguard wireguard-tools wireguard-dkms
Then use the same commands to install WireGuard on your local Ubuntu computer (the VPN client). Note that you also need to install the openresolv
package on the client to configure DNS server.
sudo apt install openresolv
Step 2: Generate Public/Private Keypair
Server
Run the following command on the Ubuntu server to create a public/private key pair, which will be saved under /etc/wireguard/
directory.
wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
Client
Run the following command to create a public/private key pair on the local Ubuntu computer (the VPN client).
wg genkey | sudo tee /etc/wireguard/client_private.key | wg pubkey | sudo tee /etc/wireguard/client_public.key
Step 3: Create WireGuard Configuration File
Server
Use a command-line text editor like Nano to create a WireGuard configuration file on the Ubuntu server. wg0
will be the network interface name.
sudo nano /etc/wireguard/wg0.conf
Copy the following text and paste it to your configuration file. You need to use your own server private key and client public key.
[Interface] Address = 10.10.10.1/24 ListenPort = 51820 PrivateKey = cD+ZjXiVIX+0iSX1PNijl4a+88lCbDgw7kO78oXXLEc= [Peer] PublicKey = AYQJf6HbkQ0X0Xyt+cTMTuJe3RFwbuCMF46LKgTwzz4= AllowedIPs = 10.10.10.2/32
Where:
- Address: Specify the private IP address of the VPN server. Here I’m using the 10.10.10.0/24 network range, so it won’t conflict with your home network range. (Most home routers use 192.168.0.0/24 or 192.168.1.0/24). 10.10.10.1 is the private IP address for the VPN server.
- PrivateKey: The private key of VPN server, which can be found in the
/etc/wireguard/server_private.key
file on the server. - ListenPort: WireGuard VPN server will be listening on UDP port 51820, which is the default.
- PublicKey: The public key of VPN client, which can be found in the
/etc/wireguard/client_public.key
file on the client computer. - AllowedIPs: IP addresses the VPN client is allowed to use. In this example, the client can only use the 10.10.10.2 IP address inside the VPN tunnel.
Save and close the file. (To save a file in Nano text editor, press Ctrl+O
, then press Enter to confirm. Press Ctrl+X
to exit.)
Change the file permission mode so that only root user can read the files.
sudo chmod 600 /etc/wireguard/ -R
Client
Use a command-line text editor like Nano to create a WireGuard configuration file on your local Ubuntu computer. wg-client0
will be the network interface name.
sudo nano /etc/wireguard/wg-client0.conf
Copy the following text and paste it to your configuration file. You need to use your own client private key and server public key.
[Interface] Address = 10.10.10.2/24 DNS = 10.10.10.1 PrivateKey = cOFA+x5UvHF+a3xJ6enLatG+DoE3I5PhMgKrMKkUyXI= [Peer] PublicKey = RaoAdsIEIwgV9DHNSubxWVG+nZ1GP/c3OU6A/efBJ0I= AllowedIPs = 0.0.0.0/0 Endpoint = 12.34.56.78:51820 PersistentKeepalive = 25
Where:
- Address: Specify the private IP address of the VPN client.
- DNS: specify 10.10.10.1 (VPN server) as the DNS server. It will be configured via the
resolvconf
command. You can also specify multiple DNS servers for redundancy like this:DNS = 10.10.10.1 8.8.8.8
- PrivateKey: The client’s private key, which can be found in the
/etc/wireguard/client_private.key
file on the client computer. - PublicKey: The server’s public key, which can be found in the
/etc/wireguard/server_public.key
file on the server. - AllowedIPs: 0.0.0.0/0 represents the whole Internet, which means all traffic to the Internet should be routed via the VPN.
- Endpoint: The public IP address and port number of VPN server. Replace 12.34.56.78 with your server’s real public IP address.
- PersistentKeepalive: Send an authenticated empty packet to the peer every 25 seconds to keep the connection alive. If PersistentKeepalive isn’t enabled, the VPN server might not be able to ping the VPN client.
Save and close the file.
Change the file mode so that only root user can read the files.
sudo chmod 600 /etc/wireguard/ -R
Step 4: Enable IP Forwarding on the Server
In order for the VPN server to route packets between VPN clients and the Internet, we need to enable IP forwarding. Edit sysctl.conf
file.
sudo nano /etc/sysctl.conf
Add the following line at the end of this file.
net.ipv4.ip_forward = 1
Save and close the file. Then apply the changes with the below command. The -p option will load sysctl settings from /etc/sysctl.conf file. This command will preserve our changes across system reboots.
sudo sysctl -p
Step 5: Configure IP Masquerading on the Server
We need to set up IP masquerading in the server firewall, so that the server becomes a virtual router for VPN clients. I will use UFW, which is a front end to the iptables firewall. Install UFW on Ubuntu with:
sudo apt install ufw
First, you need to allow SSH traffic.
sudo ufw allow 22/tcp
Next, find the name of your server’s main network interface.
ip addr
As you can see, it’s named ens3
on my Ubuntu server.
To configure IP masquerading, we have to add iptables command in a UFW configuration file.
sudo nano /etc/ufw/before.rules
By default, there are some rules for the filter
table. Add the following lines at the end of this file. Replace ens3
with your own network interface name.
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o ens3 -j MASQUERADE
# End each table with the 'COMMIT' line or these rules won't be processed
COMMIT
In Nano text editor, you can go to the end of the file by pressing Ctrl+W
, then pressing Ctrl+V
.
The above lines will append (-A) a rule to the end of of POSTROUTING chain of nat table. It will link your virtual private network with the Internet. And also hide your network from the outside world. So the Internet can only see your VPN server’s IP, but can’t see your VPN client’s IP, just like your home router hides your private home network.
By default, UFW forbids packet forwarding. We can allow forwarding for our private network. Find the ufw-before-forward
chain in this file and add the following 3 lines, which will accept packet forwarding if the source IP or destination IP is in the 10.10.10.0/24
range.
# allow forwarding for trusted network -A ufw-before-forward -s 10.10.10.0/24 -j ACCEPT -A ufw-before-forward -d 10.10.10.0/24 -j ACCEPT
Save and close the file. Then enable UFW.
sudo ufw enable
If you have enabled UFW before, then you can use systemctl to restart UFW.
sudo systemctl restart ufw
Now if you list the rules in the POSTROUTING chain of the NAT table by using the following command:
sudo iptables -t nat -L POSTROUTING
You can see the Masquerade rule.
Step 6: Install a DNS Resolver on the Server
Since we specify the VPN server as the DNS server for client, we need to run a DNS resolver on the VPN server. We can install the bind9 DNS server.
sudo apt install bind9
Once it’s installed, BIND will automatically start. You can check its status with:
systemctl status bind9
Sample output:
● named.service - BIND Domain Name Server Loaded: loaded (/lib/systemd/system/named.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2020-05-17 08:11:26 UTC; 37s ago Docs: man:named(8) Main PID: 13820 (named) Tasks: 5 (limit: 1074) Memory: 14.3M CGroup: /system.slice/named.service └─13820 /usr/sbin/named -f -u bind
If it’s not running, start it with:
sudo systemctl start bind9
Edit the BIND DNS server’s configuration file.
sudo nano /etc/bind/named.conf.options
Add the following line to allow VPN clients to send recursive DNS queries.
allow-recursion { 127.0.0.1; 10.10.10.0/24; };
Save and close the file. Restart BIND9 for the changes to take effect.
sudo systemctl restart bind9
Then you need to run the following command to allow VPN clients to connect to port 53.
sudo ufw insert 1 allow in from 10.10.10.0/24
Step 7: Open WireGuard Port in Firewall
Run the following command to open UDP port 51820 on the server.
sudo ufw allow 51820/udp
Step 8: Start WireGuard
server
Run the following command on the server to start WireGuard.
sudo wg-quick up /etc/wireguard/wg0.conf
To stop it, run
sudo wg-quick down /etc/wireguard/wg0.conf
You can also use systemd service to start WireGuard.
sudo systemctl start [email protected]
Enable auto-start at system boot time.
sudo systemctl enable [email protected]
Check its status with the following command. Its status should be active (exited)
.
systemctl status [email protected]
Now WireGuard server is ready to accept client connections.
Client
Start WireGuard.
sudo systemctl start [email protected]
Enable auto-start at system boot time.
sudo systemctl enable [email protected]
Check its status:
systemctl status [email protected]
Now go to this website: https://icanhazip.com/ to check your public IP address. If everything went well, it should display your VPN server’s public IP address instead of your client computer’s public IP address.
You can also run the following command to get the current public IP address.
curl https://icanhazip.com
Troubleshooting Tips
You can ping from the VPN server to VPN client (ping 10.10.10.2
) to see if the tunnel works. If you see the following error message in the ping,
ping: sendmsg: Required key not available
it might be that the AllowedIPs
parameter is wrong, like a typo. After fixing the typo, restart both the VPN server and VPN client.
If the VPN tunnel is successfully established, but the client public IP address doesn’t change, that’s because the masquerading or forwarding rule in your UFW config file is not working. I once had a typo in the /etc/ufw/before.rules
file, which caused my computer not being able to browse the Internet.
Note that I don’t recommend using SaveConfig=true
in the [Interface]
section of the WireGuard configuration file. SaveConfig
tells WireGuard to save the runtime configuration on shutdown. So if you add additional [Peer]
in the configuration file and then restart WireGuard, your newly-added configs will be overwritten.
If your VPN still doesn’t work, try restarting the VPN server.
sudo systemctl restart [email protected]
Then stop the VPN client.
sudo systemctl stop [email protected]
And upgrade software packages on the VPN client.
sudo apt update; sudo apt upgrade
Next, reboot the VPN client.
sudo shutdown -r now sudo systemctl start [email protected]
Speed Comparison between WireGuard & OpenConnect
On one of my VPS servers, I installed both WireGuard and OpenConnect VPN server. The speed test is as follows. It might not look like fast to you, because the connection between my computer and the VPN server is very poor. How fast you can get depends on the latency and packet loss rate between the VPN client and VPN server.
- WireGuard is the winner. It’s nearly 3 times faster than OpenConnect.
- OpenConnect over TCP is faster than OpenConnect over UDP. Surprise?
WireGuard is able to reach 52296 Kbps (about 51 Mbit/s) when playing YouTube videos.
OpenConnect (TLS with TCP BBR algorithm) is able to reach 16504 Kbps (about 16 Mbit/s) when playing YouTube videos.
OpenConnect (TLS on UDP) is able to reach 12997 Kbps (about 12.7 Mbit/s) when playing YouTube videos.
Adding Additional VPN Clients
WireGuard is designed to associate one IP address with one VPN client. To add more VPN clients, you need to create a unique private/public key pair for each client, then add each VPN client’s public key in the server’s config file (/etc/wireguard/wg0.conf
) like this:
[Interface] Address = 10.10.10.1/24 PrivateKey = UIFH+XXjJ0g0uAZJ6vPqsbb/o68SYVQdmYJpy/FlGFA= ListenPort = 51820 [Peer] PublicKey = 75VNV7HqFh+3QIT5OHZkcjWfbjx8tc6Ck62gZJT/KRA= AllowedIPs = 10.10.10.2/32 [Peer] PublicKey = YYh4/1Z/3rtl0i7cJorcinB7T4UOIzScifPNEIESFD8= AllowedIPs = 10.10.10.3/32 [Peer] PublicKey = EVstHZc6QamzPgefDGPLFEjGyedJk6SZbCJttpzcvC8= AllowedIPs = 10.10.10.4/32
Each VPN client will have a static private IP address (10.10.10.2, 10.10.10.3, 10.10.10.4, etc). Restart the WireGuard server for the changes to take effect.
sudo systemctl restart [email protected]
Then add WireGuard configuration on each VPN client as usual.
Automatic-Restart When VPN Connection Drops
Sometimes the VPN connection would drop due to various reasons. You can run the following command to check if the VPN client can ping the VPN server’s private IP address (10.10.10.1). If the ping is unsuccessful, then the command on the right will be executed to restart the VPN client. ||
is the OR operator in Bash. It executes the command on the right only if the command on the left returned an error.
ping -c9 10.10.10.1 > /dev/null || systemctl restart [email protected]
The ping will be done 9 times, i.e 9 seconds. You can use a for loop in the Bash shell to make the whole command run 6 times, i.e. 54 seconds.
for ((i=1; i<=6; i++)) do (ping -c9 10.10.10.1 > /dev/null || systemctl restart [email protected]) done
Now we can create a Cron job to automate this task. Edit the root user’s crontab file on the VPN client.
sudo crontab -e
Bash isn’t the default shell in Cron. You can add the following line at the beginning of the Crontab file to make it the default.
SHELL=/bin/bash
Then add the following line at the end of this file.
* * * * * for ((i=1; i<=6; i++)) do (ping -c9 10.10.10.1 > /dev/null || systemctl restart [email protected]) done
This Cron job will run every minute, and there will be 6 checks every minute. Save and close the file.
Policy Routing, Split Tunneling & VPN Kill Switch
Now I will show you how to use policy routing, split tunneling, and VPN kill switch with WireGuard VPN. Note that it’s not recommended to use them in conjunction with each other. If you use policy routing, then you should not enable split tunneling or VPN kill switch, and vice versa.
Policy Routing
By default, all traffic on the VPN client will be routed through the VPN server. Sometimes you may want to route only a specific type of traffic, based on the transport layer protocol and the destination port. This is known as policy routing.
Policy routing is configured on the client computer, and we need to stop the VPN connection first.
sudo systemctl stop [email protected]
Then edit the client configuration file.
sudo nano /etc/wireguard/wg-client0.conf
For example, if you add the following 3 lines in the [interface]
section, then WireGuard will create a routing table named “1234” and add the ip rule into the routing table. In this example, traffic will be routed through VPN server only when TCP is used as the transport layer protocol and the destination port is 25, i.e, when the client computer sends emails.
Table = 1234 PostUp = ip rule add ipproto tcp dport 25 table 1234 PreDown = ip rule delete ipproto tcp dport 25 table 1234
Note: The client should be running Ubuntu 20.04 or up in order to configure policy routing. The ip
utility on Ubuntu 18.04 doesn’t support the ipproto
and dport
argument.
Save and close the file. Then start the WireGuard client.
sudo systemctl start [email protected]
Split Tunneling
By default, all traffic on the VPN client will be routed through the VPN server. Here’s how to enable split tunneling, so only traffic to the 10.10.10.0/24
IP range will be tunneled through WireGuard VPN. This is useful when you want to build a private network for several cloud servers, because VPN clients will run on cloud servers and if you use a full VPN tunnel, then you will probably lose connection to the cloud servers.
Edit the client configuration file.
sudo nano /etc/wireguard/wg-client0.conf
Change
AllowedIPs = 0.0.0.0/0
To
AllowedIPs = 10.10.10.0/24
So traffic will be routed through VPN only when the destination address is in the 10.10.10.0/24 IP range. Save and close the file. Then restart WireGuard client.
sudo systemctl restart [email protected]
VPN Kill Switch
By default, your computer can access the Internet via the normal gateway when the VPN connection is disrupted. You may want to enable the kill switch feature, which prevents the flow of unencrypted packets through non-WireGuard interfaces.
Stop the WireGuard client process.
sudo systemctl stop [email protected]
Edit the client configuration file.
sudo nano /etc/wireguard/wg-client0.conf
Add the following two lines in the [interface]
section.
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
Like this:
[Interface] Address = 10.10.10.2/24 DNS = 10.10.10.1 PrivateKey = cOFA+x5UvHF+a3xJ6enLatG+DoE3I5PhMgKrMKkUyXI= PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT [Peer] PublicKey = RaoAdsIEIwgV9DHNSubxWVG+nZ1GP/c3OU6A/efBJ0I= AllowedIPs = 0.0.0.0/0 Endpoint = 12.34.56.78:51820 PersistentKeepalive = 25
Save and close the file. Then start the WireGuard client.
sudo systemctl start [email protected]
Wrapping Up
That’s it! I hope this tutorial helped you install and configure WireGuard on Ubuntu. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks 🙂
What if the server uses a dynamic public IP? I would like to build this in my home server but don’t have a static public IP from my isp.
You need a domain name and a dynamic DNS service (such as no-ip.com) to translate the domain name into an IP address. Then in the client configuration file, use your domain name instead of an IP address.
You also need to configure port forwarding (UDP 51820) in your router.
I’m having a problem with the WireGuard client. When I try to restart it after setting up the VPN Kill Switch, I get an error message. Systemctl status [email protected] tells me there’s a bad integer value for option “–mark”. Is there something I’ve missed?
Comment out the PostUp and PreDown lines in the client configuration file. Then stop the WireGuard client process.
Edit the client configuration file.
Uncomment the PostUp and PreDown lines. Save and close the file. Then start the WireGuard client.
Umm, which PostUp and PreDown lines? There are two each. Here’s the file:
Am I trying to do too much?
Yes, I don’t think policy routing and VPN kill switch should be used together. With policy routing, there is traffic that will need to use the usual Internet connection. However, VPN kill switch is meant to stop the flow of the normal Internet traffic.
Okay, I deleted the Policy Routing lines and restarted Wireguard Client unsuccessfully. Here’s the output:
I wonder about the “bad integer value” that I see. I’ve obviously done something terribly wrong. What can I do to help figure this out?
What’s your output of
sudo wg show wg-client0 fwmark
? Mine isoff
I get
I must’ve missed something in the article, but I can’t tell what.
Many thanks for useful tutorials!
I just configured Wireguard server/client, but on the client I only can communicate to the server and cannot use/browse the internet as usual. I added the ‘Policy Routing’ to the client but I cannot start Wireguard.
Error:
Is the client running Ubuntu 18.04? I just found that the ip utility on Ubuntu 18.04 doesn’t support the ipproto argument.
On Ubuntu 20.04, I can find the ipproto argument when checking the man page:
man ip-rule
. It can’t be found on Ubuntu 18.04.Yes I’m using Ubuntu 18.04. I don’t think I need Policy Routing now, I just gave it a try.
But I was able to completely install Wireguard and now I’m using it.
Thank you for the very comprehensive tutorial!
From my client ip, 192.168.0.17, I should be able to ping or telnet into server ip, 192.168.0.16, Right? But I cannot
My bad, use the same ip as my internal lan, rather a separated tunnel.
Hi Xiao Guoan,
Great turorial, precise, clear and easy to follow.
I still have a couple of questions:
1- about DNS: is there a way, in WireGuard server configuration, NOT to alter Client’s DNS like we can do in OpenVPN? I use Stubby for encrypted DNS (I followed your tutoral for that) and I surely do NOT want to use the ones on my Server side.
2- is there a way to ‘see’ that Wireguard is in use (like you can see when you use OpenVPN a little ‘lock’)?
Thanks in advance,
If you don’t want to use the server-side DNS resolver, edit the WireGuard client configuariton file.
Remove the following line from the file.
Save and close the file. Then restart WireGuard client.
Actually, using 10.10.10.1 as DNS resolver will also encrypt your DNS queries. I don’t think you need to stick with Stubby.
When the VPN client is running in command line mode, there’s no way to indicate that you are using VPN on your desktop environment. The only way to know is to check your current public IP address.
Thanks for your answers.
It seems clear if I don’t use the DNS line in the client conf, it does mean then WireGuard on the Server side will use the DNS from my client, right?
Besides, I keep Stubby for my OpenVPN connection
No. The server will use its own DNS resolver.
i want to connect to vpn server with wiregaurd app on windows
i downloaded it and i gave it the “wg-client0.conf” file. this is the error that app gave me:
2020-07-31 02:32:23.616721: [MGR] Starting WireGuard/0.1.1 (Windows 10.0.18363; amd64)
2020-07-31 02:32:23.622721: [MGR] Starting UI process for user ‘[email protected]’ for session 1
2020-07-31 03:28:37.195610: [MGR] Exited UI process for user ‘[email protected]’ for session 1 with status 0
2020-07-31 16:01:46.511021: [MGR] Starting WireGuard/0.1.1 (Windows 10.0.18363; amd64)
2020-07-31 16:01:46.520022: [MGR] Starting UI process for user ‘[email protected]’ for session 1
2020-07-31 16:02:03.899022: [TUN] [wg-client0] Starting WireGuard/0.1.1 (Windows 10.0.18363; amd64)
2020-07-31 16:02:03.900022: [TUN] [wg-client0] Watching network interfaces
2020-07-31 16:02:03.902023: [TUN] [wg-client0] Resolving DNS names
2020-07-31 16:02:03.910023: [TUN] [wg-client0] Unable to resolve one or more DNS hostname endpoints: No such host is known.
2020-07-31 16:02:03.932020: [TUN] [wg-client0] Shutting down
2020-07-31 16:07:04.281539: [MGR] [wg-client0] Tunnel service tracker finished
2020-07-31 16:07:10.150539: [TUN] [wg-client0] Starting WireGuard/0.1.1 (Windows 10.0.18363; amd64)
2020-07-31 16:07:10.151538: [TUN] [wg-client0] Watching network interfaces
2020-07-31 16:07:10.153538: [TUN] [wg-client0] Resolving DNS names
2020-07-31 16:07:10.163538: [TUN] [wg-client0] Unable to resolve one or more DNS hostname endpoints: No such host is known.
2020-07-31 16:07:10.163538: [TUN] [wg-client0] Shutting down
Maybe you missed some parts. Is your DNS running?
Did you make these parts?
systemctl status bind9
Edit the BIND DNS server’s configuration file.
sudo nano /etc/bind/named.conf.options
Add the following line to allow VPN clients to send recursive DNS queries.
allow-recursion { 127.0.0.1; 10.10.10.0/24; };
Then you need to run the following command to allow VPN clients to connect to port 53.
sudo ufw insert 1 allow in from 10.10.10.0/24
Hi Xiao Guoan
I really love your awesome tutorials!!! Please dont stop and keep going on!!!
So I finally configured my own wireguard using your tutorial.
I have a question. I have changed the server wg0.conf “allowed client IP 10.10.10.2/32” to 10.10.10.2/24 “so that I am now able to have VPN tunnels with more clients but my VPN Clients are not able to ping eachother. please give me some advice on how to allow ping between VPN clients.
Thanks in advance
AN
Okii I notice a problem here. As soon as I changed the server wg0.conf “allowed client IP 10.10.10.2/32” to 10.10.10.2/24. So that I could have more VPN clients, e.g. 10.10.10.2,3,4 — / 24, and I was also able to surf the Internet with clients who had a public IP address through a tunnel. Everything was great. But I had always lost the packet. So something I could ping “10.10.10.1” and sometimes I couldn’t ping. After that i changed the server wg0.conf back to “allowed client IP 10.10.10.2/32”. So now i had no packet lose and everything was working great.
But now i have two questions.
How should I have more VPN clients? without lossing packets. In your tutorial, I can only have one VPN-client.
How can I allow ping between VPN clients?
Thanks in advance
AN
WireGuard is designed to associate one IP address to one VPN client.
To add more VPN clients, you need to create a unique private/public key pair for each client, then add each VPN client in the server’s config file (/etc/wireguard/wg0.conf) like this:
Then configure each VPN client as usual.
Thanks Xiao it works perfect. Yes you’r right every client should have a unique private/public key. I just didnt notice that. Thanks mate : )
Hi Xiao Guoan,
What a fantastic tutorial you have done! Awesome work
I have followed it to a tee i thought, though the status of the server is showing as “inactive (dead) when i use the wg-quick up command to run it and even the alternative command to start the server results in the same. i have restarted Ubuntu 20.04 and still same also. Any ideas where to start looking to resolve at all?
Check the log.
Hi Xiao,
I am not sure what it all means 🙂 , i know enough IT to follow your tutorial, just not enough linux to know what to do 🙂 This is the log output;
— Logs begin at Tue 2020-08-11 19:49:47 AEST, end at Sat 2020-08-15 18:56:29 AEST. —
Aug 15 14:08:35 Wattserver systemd[1]: Starting WireGuard via wg-quick(8) for wg0…
Aug 15 14:08:35 Wattserver wg-quick[173330]: wg-quick: `wg0′ already exists
Aug 15 14:08:35 Wattserver systemd[1]: [email protected]: Main process exited, code=exited, status=1/FAILURE
Aug 15 14:08:35 Wattserver systemd[1]: [email protected]: Failed with result ‘exit-code’.
Aug 15 14:08:35 Wattserver systemd[1]: Failed to start WireGuard via wg-quick(8) for wg0.
Aug 15 14:10:17 Wattserver systemd[1]: Starting WireGuard via wg-quick(8) for wg0…
Aug 15 14:10:17 Wattserver wg-quick[173379]: wg-quick: `wg0′ already exists
Aug 15 14:10:17 Wattserver systemd[1]: [email protected]: Main process exited, code=exited, status=1/FAILURE
Aug 15 14:10:17 Wattserver systemd[1]: [email protected]: Failed with result ‘exit-code’.
Aug 15 14:10:17 Wattserver systemd[1]: Failed to start WireGuard via wg-quick(8) for wg0.
Maybe there’s already a WireGuard process running. Stop it.
Then use systemd service to start WireGuard.
Worked! your the best Xiao! I will now go the next step and test from client.
Hi Xiao,
pinging from iOS after connecting WireGuard client and getting ‘204 bytes from xxx.xxx.x.xxx: Destination Unreachable’ . Any ideas of the issue here? Many thanks again
Thanks for this great tutorial. I am also trying to install Subspace (https://github.com/subspacecommunity/subspace) for self service configs with SSO. Subspace runs in a Docker container on the WireGuard server. It provides DNS (runs dnsmasq) which conflicts with anything running on port 53 on the WireGuard host. Do you have any recommendations for what to change/exclude from your instructions to deal with that?
Specifically with Ubuntu 20.04.
Dear Xiao Guoan,
Thank you so much for this tutorial. After repeatedly breaking my head over wireguarding to my ubuntu server, I finally made it with your help. Unfortunately most other tutorials don’t go into the iptables details and just make do with the conf files. I have found other tutorials made by you equally helpful. Pl. keep up the good work.
Hi Xiao Guoan
I follow your procedure and install on UBuntu 20,
I think I hit the wall, when I edit the before.rule file. I can’t get my UFW running.
it always say this error.
Problem running ‘/etc/ufw/before.rules’
[15:21] [localhost.com ~] # iptables -t nat -L POSTROUTING
and line 9 is in before rules is the iptable filter
here is my before.rule conf
could you point me to the right direction of troubleshooting this issues.
thanks
Jay
Hello Xiao!
I installed bind9 per your instructions, but when I try to start it it fails. I get an error message saying “/etc/bind/named.conf.options:25: unknown option ‘allow_recursion’ ” It worked before, but now the server is broken. If ‘allow_recursion’ is an unknown option, I must have missed something, but I can’t tell what.
Okay, I found the typo in named.conf.options; it was allow_recursion when it should have been allow-recursion. Got that problem fixed, but when I start Wireguard on the client it fails with the following status:
I checked the wg-client0.conf file, and it’s exactly as you specified in the Policy Routing section. Can you shed any light on this subject?
You know, all this computer stuff would be easier if I learned to type. I found the problem here; another typo. It should have been = after PostUp instead of -.
I don’t understand, though, why my Internet access stops after a few minutes. Web pages won’t load, email won’t send, nothing, but only after Wireguard has been running for a few minutes. At first everything works just fine. Do I need to tweak the PersistentKeepAlive parameter?
Hi Xiao, thanks for your great work, as always it was an awesome tutorial.
Unfortunately, I have a problem with WireGuard in MacOS. After it connects to the server, I can resolve websites IP address and ping them, but can’t open them in any browser.
Here are my configurations:
Server (Ubuntu 18.04 with kernel 5.4):
Client (MacOS Catalina):
WireGuard log in MacOS (1. connect, 2. try to open some websites, 3. disconnect):
Could you help me with this, please?
P.S: My iPhone doesn’t have any problem with the same config (with a different IP address and keys) and opens all websites without any problem.
Maybe you should shut down the WireGuard server.
Delete the following line in the server config file.
Configure the [peer]s.
Then start the WireGuard server.
Hi there.
I read a few winguard guides today. I have an ubuntu 20.04 server (wireguard server) and wanted to connect several devices to it (windows desktop pc, mobile phones)… I like your guide as it is very clear, but unfortunately, two things did not work for me.
1. the stuff from step 5 (# NAT table rules lines) did not work for me at the end of /etc/ufw/before.rules (with only one COMMIT line), so I had to move them to the start of the file and add COMMIT immediately after them.
2. once VPN was established I could only ping the client from the server (10.x.x.x IPs) and vice versa, both client’s traffic did not reach the internet. I found these two lines in another guide, and after I put them to my server’s wg0.conf, everything started to work ok:
So… did I mess something, or are these actually needed?
Cheers!
The two things are actually one thing. The VPN clients can’t browser the Internet because the firewall rules are not set up correctly.
By default, there’s only one table (the
filter
table) in the/etc/ufw/before.rules
file. Each table must end with aCOMMIT
line, so there’s only oneCOMMIT
in this file and there’s nothing wrong with it. You can add thenat
table rules at the end of this file.The iptables rules in the
PostUp
andPostDown
are actually meant to do the same thing as I instructed in step 5: set up masquerading and allow forwarding for the private network.It might be easier to add these rules directly in the
wg0.conf
file. However, what if you have another VPN server like OpenConnect VPN running on the same host? If the WireGuard VPN server shuts down, then the firewall rules will also be deleted, and the OpenConnect VPN server won’t be working. By adding the firewall rules in the UFW config file instead ofwg0.conf
file, this won’t happen.You are the best 🙂 Thanks 🙂
Nice guide, thanks!
On the wireguard client side your solution has got the problem that openresolv does not use the local “hosts” file. So I changed my setup as follows:
NO openresolv installation
sudo nano /etc/dnsmasq.conf:
Change Network Manager settings for the physical NIC as shown in the pic, so Network Manager will not override /etc/resolv.conf anymore.
sudo nano /etc/resolv.conf:
NO DNS entry in wg-client0.conf, but:
“Endpoint = target_url.nia:51820”
and an alias for raising the wireguard interface:
“wgup=’ping -4 -q -c1 -w5 target_url.nia && systemctl start [email protected]'”
in order to have target_url.nia resolved in DNS cache already.
I also suggest to disable ipv6 with: GRUB_CMDLINE_LINUX=”ipv6.disable=1″ whenever ipv6 is not needed for the VPN connection.
In contrast openresolv does no caching for the nameserver 10.10.10.1, so the dnsmasq solution is generally faster when dealing with lots of URLs from the internet.
My Ubuntu desktop computer uses

openresolv
and/etc/hosts
file works like a charm. If you edit an entry in/etc/hosts
file, but it doesn’t seem to work, it’s perhaps because your web browser caches DNS results. You can clear your browser cache or restart the web browser.openresolv
is just a framework for managing the content of the/etc/resolv.conf
, i.e, setting the DNS server address. No more and no less. It’s not a local DNS resolver like dnsmasq.dnsmasq
was replaced bysystemd-resolved
since Ubuntu 16.10. You should not compareopenresolv
withdnsmasq
, because they are meant for doing different tasks. Rather, you should comparesystemd-resolved
withdnsmasq
.systemd-resolved
does have caching capability.And it uses
/etc/hosts
file per default. If you take a look at/etc/systemd/resolved.conf
file, you can find the following line.By default, Network Manager won’t override the DNS server setting in
/etc/resolv
file. As you can see from the screenshot below, I have 127.0.0.1 set as the DNS server in Network Manager.I always recommend using the default software on Ubuntu operating system rather than using alternative software, unless you really need to get a feature that’s not available in the default software.
Right you are. Meanwhile with another fresh setup of the ubuntu wireguard client /etc/hosts is being used properly.
However, systemd-resolved does not cache on client side:
where 30ms is about the ping time:
Also I have to know all LAN IPs on server side, as bind9 there does not resolve them via 10.10.10.1, so the only way is to put all corresponding entries into “/etc/hosts” on my client. In this special case we have to register 14 computing nodes inside the server LAN plus 4 more in an DMZ plus a couple of non-computing devices. I would’nt know how to avoid these hosts entries altogether.
When using
openresolv
to set 10.10.10.1 as DNS server, DNS requests are sent directly to the 10.10.10.1 resolver, so there’s no cache.You can remove
openresolv
(sudo apt remove openresolv), removeDNS = 10.10.10.1
from thewg-client0.conf
file and set the DNS resolver directly in systemd-resolved.You can set multiple DNS resolvers in this file like so:
Save and close the file. Then
I like this, going to implement it right away. Thanks!
Another little problem: Whenever openresolv kicks in, names in the client LAN do not get resolved anymore, as the nameserver at 10.10.10.1 does not know anythinǵ about them. So have to put all my clients LAN nodes into /etc/hosts as well.
I’m running WireGuard on my server and my laptop, per these instructions. I find, however, when I try to access the CUPS web interface and add (and share) a printer, I get a message reading “Forbidden” and on the next line “You cannot access this page.” Do I need to open another port (presumably 631) in the firewall? It worked well before installing WireGuard.
If your WireGuard VPN server and CUPS print server are running on the same box, and you want to access the CUPS web interface via 10.10.10.1:631, then you need to add the 10.10.10.0/24 IP range to the CUPS whitelist.
Edit the
/etc/cups/cupsd.conf
file and add the 10.10.10.0/24 IP range to the whitelist.Save and close the file. Then restart CUPS for the changes to take effect.
Also, allow clients in 10.10.10.0/24 to access port 631.
Worked like a charm!
Hi
Thanks for another great tutorial…
One question:
Did you mean to remove the Port 22 from ufw at then end of the procedure?
As I thought VPN port was meant to be the only entry through ufw.
Then once VPN is connected then Port 22 for ssh can be connected only from 10.10.10.0/24 based on rule –> ALLOW Anywhere From 10.10.10.0/24
Isn’t that right?
Perhaps you have removed Port 22 from ufw somewhere I missed.
Thanks again,
Really appreciate the welth of tutorials..
Andras
This tutorial didn’t close port 22 from public access, but you can do so.
Closing port 22 carries a risk in that if your VPN server stops working, you would lock yourself out. If your VPS hosting provider allows VNC Console access, you can use the console to access the server and fix this problem.
My reason to think about implementing this VPN setup was because, on my servers I am now encountering houndreds of Fail2Ban Bans over SSH port, that it made me feel like I want to turn SSH port off.
At the same time I need to SSH into my servers for the obvious reason of maintenance, evry now and then.
So I thought I would implement a VPN server on every single one of my servers, so only when I am connected together a certain server through VPN, only then it would be possible to SSH into it.
Hence I thought Port 22 could be closed towards the public.
Thanks again,
Yes, you can set up VPN server on every server and add all the server IP addresses to the firewall whitelist, so if one VPN server stops working, you can connect to another VPN server and have SSH access. This greatly reduces the risk of locking yourself out.
Hi,
Thanks again for your tutorials.
It seems that there is something which doesn’t run properly on bind9.
Is the following output from my terminal nominal?
Thanks in advance
It indicates your server network doesn’t provide IPv6 connectivity. You need to disable IPv6 in BIND.
Disable IPv6 in BIND on Ubuntu 20.04
open the /etc/default/named file
Add
-4
to the OPTIONS.Save and close the file. Then restart BIND and you are done.
Disable IPv6 in BIND on Ubuntu 18.04
Open the /etc/default/bind9 file
Add “-4” to the OPTIONS.
Save and close the file. Then restart BIND and you are done.
Thanks Xiao, it solved the issue.
Hello thanks for the tutorial.
I’m very new to this and it seems I’m able to follow the guide up to the end where enabling the wg service from the client
but after that the I cannot connect to the client (raspberry pi) anymore locally on my PC and when checking the IP of the client it seems to use my Server IP. When I stop the service My PC can connect to my client again.
Is this how it should bahave?
VPN can change a client’s public IP address, so connections to the old public IP address will be dropped. A working VPN does not affect a client’s LAN connection.
Okay, got.
Then all I have to do is also add my PC as a additional client and connect to wireguard server to be connect to my client (raspberry).
Thanks for the quick response.
Hi Xiao,
Thank you for such an awesome and extensive article. I’ve seen a lot of content on setting up WireGuard, and yours is simply the best. Would you be able to elaborate on how to set up Wireguard to work with multiple IPs as exit points? For example, I have two IPs with my server that are both added to the same networking interface. I can use both as IPs endpoints to my clients to access and forward traffic on my server. However, both IPs still resolve to the same IP address on exit. So no matter which IP I use on the Wireguard client, when browsing and checking my IP, they both resolve to the default IP address of the server. I’ve search everywhere and unable to find a proper set up.