Complete Wireguard Setup in 20 min – A BETTER way to VPN

Wireguard is the future of VPN. Setting up a Wireguard VPN server couldn't be easier. In this tutorial, I will show you how to create a Wireguard server on a Linux machine.

In March 2020, the Wireguard protocol was officially added to the Linux kernel. Since then it has been back-ported and tools were built to let it run on nearly any platform. The Wireguard VPN server protocol is the same across distributions, so the following setup instructions will be the same for any Linux machine.

For Windows, check out our Wireguard server on Windows guide.

As stated in the Wireguard Introduction article, one of the best features of Wireguard VPN is how easy it is to get started. It follows a similar pattern to SSH key pair generation.

This Wireguard setup guide will lead you through creating a server configuration file and a client configuration file. They each contain a few components and are complementary to each other. We need to create a new client configuration file for each device we want to connect to the Wireguard server.

Wireguard Overview

For those unfamiliar with the Wireguard protocol, it involves creating a private key (randomized characters) and a public key (more randomized characters derived from the private key) that are used in a sort of "lock" and "key" mechanism. The difference here is that we will be creating these keys for both the server and each client so that authentication happens in both directions, creating a tunnel.

Wireguard tunnel can be useful in many ways. For example, you could use the tunnel to route your DNS traffic (looking up websites) to a Pi-hole, accessing your home server from anywhere, or even passing ALL of your internet traffic through the Wireguard server - and all done securely. [Read: Complete Pi Hole setup guide: Ad-free better internet in 15 minutes]

This is exactly how I setup my Wireguard VPN server, alongside a Pi-hole, to let me securely browse the web from any device, anywhere in the world.

In this article, I will use the word "server" to refer to the primary machine that will act like a hub, and "client" to refer to any devices connecting to it (like your phone, laptop, desktop, etc.).
SmartHomeBeginner brings in-depth tutorials easy enough to understand even for beginners. This takes considerable amount of work. If this post helps you, please consider supporting us as a token of appreciation:

  • Feeling generous? Buy me a coffee (or two).
  • May be another day? Shop on Amazon using our links. Your prices won't change but we get a small commission.
  • Don't feel like spending? You can still show your support by sharing this post, linking to it in forums, or even commenting below.

Install Wireguard

I will be giving the instructions for installing on Ubuntu 20.04 since it is a commonly used server. Have a look at the Wireguard website for specific instructions on getting the Wireguard tools installed on your machine.

Install Wireguard
Wireguard is available on nearly every popular platform!

Wireguard installation is the easy part. Configuration is the more time consuming step. First, let's start with the basics.

Wireguard Prerequisites

  • Just about any Linux distribution with root privileges
  • Familiarity with Linux command line
  • Public IP address (exposed to the internet) or a domain name pointing to your server

Wireguard Setup on Ubuntu

As we are on an Ubuntu server, installation is quick:

sudo apt update && sudo apt install wireguard

A number of libraries related to Wireguard cryptography (encryption) will be installed along with the main utility. That's it. Let's configure it and start the server.

Server Key Generation and Configuration

Wireguard's included set of utilities allow us to quickly create public/private keypairs. These are used to authenticate incoming traffic to the server. You can think of the private key like the lock in a door, while the public key is like a physical key used to unlock it. The server's private key should never be shared. The public key is what we will give to the clients so they can connect to our server.

Both of these keys, but ESPECIALLY the private key, must be kept secure. DO NOT send these to your friends or anyone for that matter over an insecure protocol like Facebook Messenger or likewise!

Wireguard Key Security Preparation

To keep everything secure, change to your root account while we run the next set of commands:

sudo -i
cd /etc/wireguard
umask 077

We use the command umask to set permissions for any files we are about to create. Umask is subtractive, in that it removes permissions. In the command above, we are removing all permissions (noted by the 7's) from "group" and "other" users.

Be aware that the permission mask only lasts for the current session. So when you logout and log back in, you will need to use the command again to make sure any newly created credentials have the same restricted permissions.

Private Key Generation: The Lock

We begin by generating the private key. These sets of commands will always start with wg, which is the first set of Wireguard tools we will be using. Remember, this first one is like creating our server's "lock":

wg genkey > server.key

By default, the above command will output the result to the screen. But since we are using the > modifier, the result will be pushed into a file (and create the file first if it doesn't exist). Note that if you use this modifier with an existing file, it will be overwritten!

With the above command, we generated a private key and pushed it into a new file called server.key.

Public Key Generation: The Key

Next we use a similar command, but this time we derive the public key from the private one. This gives us the public "key" to match the private "lock":

wg pubkey < server.key > server.pub

Similar to the above, but this time we are using the opposite < sign to first read the contents of our private key into the pubkey function. The result of that is (just as above) pushed into a new file called server.pub. This public key is one of the components our clients will need to access the Wireguard server.

With these two components, we can now create our Wireguard configuration file which will let us start the server!

Server Configuration file

Create the configuration file called wg0.conf in the default Wireguard directory (/etc/wireguard). This file will later be read by Wireguard to create and configure a virtual interface.

You don't need to know much about how virtual interface works, but think of it like a door that holds the lock and key. We are adding a digital ethernet/WiFi adapter - except that any data passing through it is automatically encrypted and sent to your other Wireguard device(s).

nano /etc/wireguard/wg0.conf

Add the following lines to the beginning of the file:

[Interface]
Address = 10.254.0.1/24
ListenPort = 49312
SaveConfig = True

Save and close the file. Here we are setting the digital wg0 interface to run on a local set of IP's. This isn't strictly required, but helps to organize your machine so there are no conflicts or overlapping IP addresses later on. Note that you can choose any set of IP's in the private IP ranges (192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12).

We have attached the /24 CIDR notation to the end of the IP address to indicate that it can use a range of addresses. For example, /24 in this scenario represents all addresses from 10.254.0.1 to 10.254.0.254. This gives us the potential to have 253 clients.

The listening port is arbitrary. Select any port you like as long as it's above 1024 (well-known/system ports), with somewhere between 49152 and 65535 recommended (private/ephemeral ports).

Lastly, we will add our private key ("lock" in the above references) into the configuration. You can output the file to screen using the cat command, copy it, open the file again, and paste it. Or, to do the same thing in a single step we can use the echo command:

echo "PrivateKey = $(cat server.key)" >> /etc/wireguard/wg0.conf

Notice how we use $(cat ...). This notation means we will run the command inside the parentheses before the remainder of the command. We are then using echo to print the output to the screen. However, instead of showing it onscreen, we use the >> to append (or add it to the end) the output to the Wireguard configuration file. Note how this is different than using a single > which would overwrite our entire file!

And that's it! We will need to revisit the configuration file shortly, but this is all that's needed to get the Wireguard server started.

Your finished config file should look something like this (but a different key, as mine is just an example):

[Interface]
Address = 10.254.0.1/24
ListenPort = 49312
SaveConfig = True
PrivateKey = YIHEAqPWDJh2DsCrsDltwtRsBuxm7lEjwF8UOEcvxkM=

For now we can logout of the root account, either using Cmd + D or typing:

exit

Starting your Wireguard Server

Wireguard comes with a nice tool which takes care of most internal networking configuration. The tool will create the new digital Wireguard interface for us and set basic configurations. It will continue to run in the background as a system service. The name of the interface will match the name of the config file we just created.

Bring "Up" your Wireguard Server

sudo wg-quick up wg0

The wg-quick utility will attempt to create a new Wireguard interface using the wg0.conf file.

This should give you a sample output similar to this:

[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.254.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0

Enable Wireguard at system boot

To ensure that the Wireguard service is started at system boot, we can enable the service with the following command:

sudo systemctl enable [email protected]

Systemctl is part of systemd. Systemd controls services and special types of programs that continuously run in the background.

Your Wireguard server is now running!

Server Status

We can have a look at the status with:

sudo wg show
Wireguard start and status
Wireguard started successfully and shows the interface is up.

Ok great! We can see it is running, and we can also see that it's listening for connections by using the netstat command.

Netstat listening devices
Wireguard is listening on our desired port!

Port Forwarding and Firewalls

If you are behind a router (like a WiFi router or ISP provided unit), you will need to forward the port we used above (port 49312 or whichever you used) so that clients can actually reach our server listening for outside connections. Without this, any request from your device will be blocked at the router and never forwarded to your server. [Read: How to setup port forwarding on a router?]

Firewall

As above, we need to make sure incoming connections reach our Wireguard server. To do that we have to open the port in our firewall (if enabled). If you are using the popular UFW, we can simply issue the following command:

sudo ufw allow 49312/udp

So now we have our server running, and it is reachable from outside the network. But what good is a server without clients? Let's create a client configuration file and allow it to connect to our server.

How to Add a Client to Your Wireguard Server

Wireguard is a very simple server, but it should be noted that it does not automatically assign IP addresses like a DHCP server will. We will need to manually assign IP addresses to each client we wish to use Wireguard. This is done with client configuration files.

Create a Client Configuration File

By creating a set of client credentials, we give our devices (like a phone or computer) its own set of "lock" and "key" just like we did for the server. These private and public keys will be used to authenticate with our server. Our server has one "lock" and our client has the "key" to it. Our client also has its own separate "lock" and the server will be given the specific "key".

This is to ensure only the desired traffic is allowed to connect and go through our Wireguard server. We can add as many clients as well like by creating a new set of credentials for each.

A more comprehensive view into setting up and configuring various clients (Android, Windows, MacOS, etc.) is coming soon as a dedicated article. So check back soon.

Secure Key Preparation

Like before, we will keep everything secure, but more accessible. As your user, let's create a directory in our home folder to hold credentials.

cd ~
umask 077
mkdir wireguard && cd wireguard
mkdir peer1 && cd peer1

Notice that I also created a directory called peer1. Call it anything you like, I normally go with something identifiable like "kris-phone" and create a new directory for each of my devices.

Client Key Generation

Just as we did for the server, we will create private and public keys for our client device plus another unique key called a Pre-Shared Key (PSK), for added security. These 3 keys will allow us to create a client.

Generate the keys

wg genkey > peer1.key
wg pubkey < peer1.key > peer1.pub
wg genpsk > peer1.psk

If you skipped ahead to this section and don't understand what we are doing here, go back to the server key creation for a more in-depth explanation. The only new piece here is the additional Pre-Shared Key (PSK). The PSK is optional, but adds significant security and is very easy to add. If you've been following the "lock" and "key" theme so far, this PSK is akin to making the public "key" continuously changing, cloaking its "shape". Both the client and the server need a copy of this final PSK element.

Add Everything to a Client Config File

Many clients can read directly from this file, so we will set it up in a familiar format to the server configuration file from before:

nano peer1.conf

Paste in the following:

[Interface]
Address = 10.254.0.2/32

Save and close. Notice how the IP address changed: We incremented it above our Wireguard server's IP (10.254.0.1 in this Wireguard tutorial) and used /32 which only allocates a single address. We essentially defining the IP address for the connecting client.

We will need to increase the last number (octet) by 1 for each additional client we wish to configure in the future.

Let's add our private key to the end, using the same set of embedded commands as before:

echo "PrivateKey = $(cat peer1.key)" >> peer1.conf

This top portion of the file will help setup the interface (like a virtual WiFi adapter for your traffic to go through) on your client/device. Now we need to add the server connection details to our client configuration so the device knows where to connect to. It will be added as a "peer". Using the same "echo" trick from before, we run the following:

echo "[Peer]" >> peer1.conf
echo "Endpoint = 123.456.789.111:49312" >> peer1.conf
echo "AllowedIPs = 10.254.0.0/24" >> peer1.conf
echo "PublicKey = $(sudo cat /etc/wireguard/server.pub)" >> peer1.conf
echo "PresharedKey = $(cat peer1.psk)" >> peer1.conf

Endpoint is the public IP address of your server that we want our device to connect to. Replace the 123.456.789.111 IP address with your server's public IP or the domain name of your server.

The AllowedIPs setting let's us control what IP's in our network we will have access to. For now we will only focus on connecting to your Wireguard server, so leave this as is.

We then add the public key of our server (not the client). This gives the client the "key" to our server's "lock".

Finally we add additional security with the Pre-Shared Key. This is the "cloaking" mechanism so our "key" cannot be cracked.

Add Client to Your Server Config

Now that the client knows how to find the server, the server needs to know that the client is allowed to connect. We must add our client as a "peer" to the end of our server config file. Let's use the same echo trick as above to append the details to our server config file as the superuser:

sudo -i
cd /etc/wireguard
echo "[Peer]" >> wg0.conf
echo "AllowedIPs = 10.254.0.2/32" >> wg0.conf
echo "PublicKey = $(cat /home/user/wireguard/peer1/peer1.pub)" >> wg0.conf
echo "PresharedKey = $(cat /home/user/wireguard/peer1/peer1.psk)" >> wg0.conf

Be sure to change the file path inside the cat commands to read the correct files. This completes the exchange of "keys" so that both server and client can communicate.

We've now given the client access details for the server (using the public key and pre-shared key), and given our server the details of the client's credentials as well.

Our server config (wg0.conf) should look like the following (with different keys):

Wireguard server config with peer
Wireguard server config with a single client.

Now all we need to do is restart the Wireguard server to pickup the changes to our configuration file. We can accomplish this one of two ways:

wg-quick down wg0
wg-quick up wg0

This will stop and remove the interface, and then recreate it with the modified configuration. The second option is a sort of soft-reset which does not disrupt any ongoing connections to your Wireguard server:

wg syncconf wg0 <(wg-quick strip wg0)

This command syncs the modified configuration file with the server. If there are errors in your config syntax it will be shown on screen. We can see the changes by once again looking at the output of wg show.

Wireguard show command with client waiting
Wireguard server waiting for peer connection.

Once again we can leave the superuser session with Ctrl + D or by typing exit

At this point, you can use the client config file to setup your client device (phone, computer, etc) and it will connect to your Wireguard server. This will allow you to connect to services on your Wireguard server. An example would be to set your DNS to your Pi-hole, or accessing a private website that you normally only access at home on your host server.

Any additional clients you wish to add simply need to be appended (added) to the end of your server config file.

Relaying Traffic Within the Network

Now comes the tricky part. I know networking in general can be very confusing for beginners, so I will do my best to break down the next few sections into consumable concepts. So far we've created a server and client. The client can connect directly to the server. More clients can be created and added in the same way.

What is Relaying/IP Forwarding?

If we have multiple clients, and you want to connect from one client to another it will require an extra step (relaying). For example: You are on your laptop (client device) at a friend's house, but want to connect to your desktop (client device) at home:

  • Wireguard VPN server is running on your Raspberry Pi, with IP 10.254.0.1.
  • Your laptop is connected as a client to your Raspberry Pi's Wireguard server using IP 10.254.0.2.
  • The desktop at home is connected as a client to your Raspberry Pi's Wireguard server using IP 10.254.0.3.

To connect from your laptop to your desktop (10.254.0.2 --> 10.254.0.3), we must enable IP forwarding on the Raspberry Pi. This would also be required if you are away from home, and wanted to securely connect to your smart home devices using Wireguard.

Add IP forwarding

Enabling IP forwarding involves modifying the system file /etc/sysctl.conf on the wireguard server.

Open the file and uncomment the line for net.ipv4.ip_forward=1, or even easier, we can use the built-in "Small Editor" sed command to do it for us:

sudo sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf

Essentially we are replacing a commented out line with an uncommented line (removing the leading #) and enabling IP forwarding. This is a very cool tool that can save loads of time searching through config files. The -i flag means we want to edit the file "in-place" and make the changes directly.

The syntax of the next part is a bit odd, but goes like this: s is for "substitute", everything in between the next pair of slashes (/#net.ipv4.ip_forward=1/) is what it will search for, while everything between the next pair of slashes (/net.ipv4.ip_forward=1/) is what sed will replace it with.

Finally we just tell it which file we want it to work on. This is a quick demonstration of a tool that has 1000x more usefulness!

Apply IP Forwarding Permanently

To apply the setting, we must use the following:

sudo sysctl -p

This will make our above setting permanent, and should be reflected in the output of the command.

With this setting enabled, you should now be able to connect from one Wireguard peer to another Wireguard peer (through your server).

Example Use Case: From outside your home, connect to a VNC Server running on Ubuntu, which is also connected to the same wireguard server as a client from either inside or outside your home.

Access Non-Wireguard Devices on Your Home Network

To access other devices in your home network (they don't necessarily HAVE to be connected to your Wireguard server), you will need to append your "AllowedIPs" in the client config file. If you wanted to connect to other devices on the 192.168.0.0 network for example, it could look something like this:

...
AllowedIPs = 10.254.0.0/24, 192.168.0.0/16
...
Example Use Case: From outside your home, connect to a Plex or Jellyfin server (not connected to the wireguard server) to watch media.

Access the Internet Outside of your Home Network

To take this guide one step further, you might want your client to connect to more than just the local addresses in your home network. If you want all of your client's internet traffic to appear to come from you Wireguard router, we must route all of your client's internet traffic through your shiny new Wireguard VPN server. To accomplish this, we have to make a few additional changes to the networking within our wireguard server. This is useful if, for example:

  • Traveling overseas, but want your internet traffic to come from your home network (or VPS)
  • Avoid a country ban (Netflix, HBO, etc.)
  • Hide your traffic from ISP's, by connecting to a Wireguard server on a VPS or your home
  • Securely browse the internet from airport or coffee shop WiFi

This is how I personally have my Wireguard setup - a VPS running Wireguard and a Pi-Hole to allow me to connect securely from anywhere with some decent ad blocking 🙂

To do this you must first enable IP forwarding (above), followed by Network Address Translation (NAT).

What is Network Address Translation (NAT)?

This part is a lot more complicated and not as easy to explain if you don't understand networking and specifically iptables. I personally struggled with this for ages. Network Address Translation (NAT) allows our devices to interact with the wider internet. In fact, your home router is already using NAT with a public IP address. When a request goes out to the internet, it uses the public IP as a "return address", just like when you send a letter in the mail.

For example: You are on your computer and type in a website address. The request leaves your computer as a packet. The packet goes through your home network to reach your router with your laptop's internal IP address attached (192.168.1.10 for example). Next, the router uses NAT to attach your home's public IP address to your website request. When the packet leaves your home router, the "return address" is the router's public IP address, and not the internal (192.168.1.10) address.

All of this happens to ensure the website request is returned to the right place (your home router and not some random computer on the internet). As the request comes back from the website, the router then translates it back to your internal address (192.168.1.10) and delivers it to your computer.

In our case, we must enable NAT for our Wireguard server so it understands that we want to allow our traffic to exit our server and reach the wider internet and vice versa.

This is also similar to services offered by many commercial VPN providers such as NordVPN, Surfshark, StrongVPN, and VyprVPN. All your internet packets are routed through their servers out into the internet and returned back to your client.

Enable NAT in your Wireguard Server

To enable NAT, we will modify our Wireguard server config. We will add a line to tell Wireguard to create an NAT table for our new VPN interface when we start Wireguard, and tear it down when we disable it. Let's edit our server config file and add the following under the "[Interface]" heading but before our first "[Peer]":

[Interface]
...

PostUp = iptables -I FORWARD 1 -i wg0 -j ACCEPT; iptables -t nat -I POSTROUTING 1 -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
...

Note that we are passing the traffic through the device "eth0". Your server may or may not be using the same device. To see which device connects to the internet, you can check with the ip addr command or use the output from:

ip -o -4 route list default | cut -d" " -f5
If the result is something other than "eth0", you must replace it in the config file above.

This time we must restart our Wireguard server to use the newly added commands:

wg-quick down wg0
wg-quick up wg0

Now your server is all set to pass traffic from local devices AND allow them to connect to the internet through your Wireguard server!

Allow Client Internet Access

The last piece is to change your client's AllowedIPs to 0.0.0.0/0. So your client configuration should look like the following (except with YOUR keys and public IP/Domain name):

[Interface]
Address = 10.254.0.2/32
PrivateKey = cD+NoV94mw7SnjOU1VTHdH6GACie8mr/VDPXXY3oI1E=

[Peer]
Endpoint = 123.456.789.111:49312
AllowedIPs = 0.0.0.0/0
PublicKey = U2oRFamuEDrOB8eds1ETQWE3nUh7VYoGvDZV0HU8lm0=
PresharedKey = GZ159PGs59WQOj5Z+SQszPz995TcERHmK3DknuQoqU=

Now your client should be able to browse the internet through your Wireguard server.

Other Useful Wireguard commands

Stop Wireguard Server

To stop your Wireguard server, simply use the command:

wg-quick down wg0

Show Wireguard Server/Client Status

wg show
SmartHomeBeginner brings in-depth tutorials easy enough to understand even for beginners. This takes considerable amount of work. If this post helps you, please consider supporting us as a token of appreciation:

  • Feeling generous? Buy me a coffee (or two).
  • May be another day? Shop on Amazon using our links. Your prices won't change but we get a small commission.
  • Don't feel like spending? You can still show your support by sharing this post, linking to it in forums, or even commenting below.

FAQs

Can I use custom DNS? Like using a Pi-Hole?

Yes, by adding the following to your client [Interface]:

DNS = 10.254.0.1

Be sure to replace with the local IP address of your Pi-Hole server.

Can I setup Wireguard with IPv6?

Yes. There are 3 additional changes:

  1. Where we added IPv4 addresses, you can add IPv6 addresses.
  2. You will also need to add (uncomment) net.ipv6.conf.all.forwarding = 1 to your sysctl.conf file.
  3. For NAT, you must also add the same rules for ip6tables in PostUp and PostDown.

Why can't I connect from client X to client Y through my Wireguard VPN server?

There could be a couple of reasons. Make sure you have IP forwarding set. If you are behind certain routers, you might need to keep a "heartbeat" where the client sends an empty, authenticated packet to let the server know where it is. This is accomplished by adding the following under your client configuration's [Peer] section:

PersistentKeepalive = 25

This sends a "ping" every 25 seconds.

How do I add more Wireguard client devices?

Repeat the same steps as above for "How to Add a Client to Your Wireguard Server". Create new private, public, and pre-shared client keys. But be sure to assign a different IP address. For example: use 10.254.0.3 if you followed along this article. Then add the same information for the new client to the server config and restart Wireguard (or use the wg syncconf command like above).

This seems like a lot of work, can it be automated?

Absolutely, there are a number of simple scripts for creating these config files quickly and easily. One example can be found in my GitHub repository, although as of writing this it is at best used as an example. Here are some other automation tools:

How do I set up my client on (Windows, Linux, Mac, iOS, Android, etc.)?

Stay tuned. A comprehensive client article is coming ASAP!

Conclusion

Wireguard VPN is the biggest thing in VPN's right now and all the big commercial VPN providers are flocking to it. The good news is it works, it's fast, and easy to setup yourself.

This guide may have looked long but if you know what you are doing it should take 15 min or less to setup Wireguard.

I am extremely happy with mine (and connecting it to a Pi-Hole). Leaving PiHole instance exposed to the internet can lead to abuse and unauthorized use to say the least. Wireguard allows me to connect securely to my server running PiHole and Wireguard and use its internal IP address as my PiHole DNS IP. Nobody else can connect or see the IP address of my PiHole instance.

My devices run through it seamlessly as well as my partners'. The work to get it setup was relatively painless. And the peace-of-mind to leave it running on my own hardware and know my data is protected is priceless.

This Wireguard setup how-to turned out to be longer than what I had imagined but I hope it helps you get started with Wireguard VPN server setup.

Did this post help you?
SmartHomeBeginner brings in-depth tutorials easy enough to understand even for beginners. If you are reading this, please consider buying us a coffee (or two) as a token of appreciation.

Kristopher

Kristopher is a tech enthusiast interested in teaching and simplifying technology for others. Online privacy and responsibility has become of upmost importance and he aims to help others reduce their reliance on tech giants.