Getting started with Wireguard
What is Wireguard
Wireguard is a fast, straightforward, secure, and incredibly easy to set up VPN that aims to be faster than other common VPNs (like OpenVPN and Ipsec) by living inside the linux kernel and using much faster cryptographic primitives. While Wireguard is available for Windows, macOS, BSD, iOS and Android, you still need a linux kernel to benefit from the extra speed. While still in development, it’s already faster than OpenVPN. Wireguard is also different from other VPNs by not utilizing a typically ‘client/server’ relationship, opting instead for peers. Any client can be a server, and any server can be a client, and the setup is almost identical for both. Wireguard uses the GPLv2 license, and even has a positive comment about its code from Linus Torvalds:
Can I just once again state my love for [WireGuard] and hope it gets merged soon? Maybe the code isn't perfect, but I've skimmed it, and compared to the horrors that are OpenVPN and IPSec, it's a work of art
In addition he pulled Wireguard VPN into the 5.6 kernel source tree on January 28th of 2020.
Wireguard encrypts the connection using a pair of cryptographic keys generated with Curve25519. This keypair is used by sharing the public key with the other peer who can then encrypt their data so that it can only be decrypted with the corresponding private key. Each peer will need each other's public key in order for a connection to be made.It also supports Pre-shared Symmetric, if you’d like to future proof for quantum computing.When a packet is sent via a Wireguard interface, the ipv4/ipv6 addresses (in CIDR) are compared with the packet’s destination address to determine where the packet should go. Also, when a packet is received from a known peer on a Wireguard interface, it is used to filter out any packets having a source address that doesn’t match these settings.
Bypassing CGNAT and PersistentKeepAliveIf you’re one of the unfortunate people who have to deal with an ISP that’s using CGNAT instead of ipv6 when dealing with the issue of ipv4 address exhaustion, you can use Wireguard as a solution around this while still maintaining high throughput.
In addition one of the other problems with having a host behind a NAT is that the NAT is monitoring for connections in order to route traffic, so if your peer is behind a NAT or a stateful firewall, you’ll want to maintain that connection by occasionally sending keepalive packets (as Wireguard is otherwise silent by default). The PersistentKeepalive =
field tells Wireguard at what interval in seconds to send a packet. Once every 25 seconds is reasonable for most configurations, which you can set with PersistentKeepalive = 25
in your interface configuration file (which we’ll set up later on in this guide).
In this guide we’ll be using Ubuntu 18.04and we’re going to be calling the two peers Client and Wireguard Server (again, any peer can be a server, there is no strict client/server relationship, but for the sake of easy understanding, these names will be used as that is in effect what we’ll be doing with this tutorial)
Step 1: Install Wireguard
Install wireguard
with the following command. This package will install all necessary dependencies.
sudo apt-get install wireguard
You can double check to make sure it's installed with
sudo wg help
If installed correctly you should see something like this:
2. Intro to wg command line tool
The wg
command is how we’ll be checking the status of wireguard as we set things up. If invoked without parameters, it’s the same as wg show
. For example, on our completed setup, invoking wg
or wg show
will produce something like this. Don’t worry about this now, this is our end result once we get through the tutorial.
The -showconf
parameter is also useful if you’d like to see how your config file is being read by wireguard for your current connection. The other commands are used for manually creating peers, and generating keys. However we’ll be setting everything up by editing .conf files so things are a little more understandable for our first go around.
2. Create the wg0.conf file for the wireguard server.
Wireguard will read from a .conf file to create the interface that you’ll be using to connect. Create the file /etc/wireguard/wg0.conf
with your editor of choice. For this tutorial, I’ll be using nano.
sudo nano /etc/wireguard/wg0.conf
Enter the following information to set up the server.
[Interface] PrivateKey = --Private Key of **Wireguard Server**-- Address = 10.0.0.1/24 ListenPort = 51820 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT
Explanation of options:
Address
specifies which address we’re assigning to the server on the vpn. You can also use ipv6 if you’d like, but in this guide we’re using ipv4.PrivateKey
is the private key for the server which we’ll generate later. We’ll need this to decrypt traffic that was encrypted for the server.PostUp
/PostDown
are keywords that define the commands that will be run when the interface is brought up or down, respectively. We’ll be using these iptables commands to set Linux IP masquerade rules to allow each peer to share the server’s IPv4 addresses. When the interface is brought down, the rules are removed.ListenPort
tells wireguard which port to use for incoming connections.
We’ll come back to this later to add our peer information and our keys. At this point, wireguard won’t work, so don’t bother to test it.
3. Set up UFW
We’re going to set up our firewall to allow SSH and wireguard tunnel traffic through on the server side.
sudo ufw allow 22/tcp
sudo ufw allow 51820/udp
(Make sure it's /udp
, wireguard is not TCP!)
sudo ufw enable
sudo ufw status verbose
4. Generate keypairs
To get started you’ll need to generate a public and private key for each peer. Wireguard encrypts the traffic with public keys so that only the intended recipient can decrypt the traffic. Any peer must have the public key of the peer it is transmitting to, and Wireguard’s config file will need the corresponding private key in order to decrypt that traffic. To put it simply, a peer is the only one that should have its own private key, and it should have the public key of any peer it sends to, and they should have their public key as well.
You’ll place each key into the ‘PrivateKey’ and ‘PublicKey’ variables in the wg0.conf file that we’ll create later. Transferring the keys between each host will be up to you, but examples ahead will show you where to play them.
Generating these keypairs is made simple with this one liner:
wg genkey | tee privatekey | wg pubkey > publickey
If you do this right you shouldn’t get any output at all. Remember, a public key is generated with a private key, and the `tee` utility is how we’re able to save the key to file and also pipe it into the next command.
You can check your keys with:
cat publickey
cat privatekey
Repeat this step for both of your peers so that they each have their own keypair. Put your private key created for the Wireguard Server into the PrivateKey
field of the Wireguard Server. We’ll be using the server’s public key in our config file for Client
3. Create the wg0.conf file for Client
Create the /etc/wireguard/wg0.conf
file again and input the following
[Interface] PrivateKey = --Privatekey of Client-- Address = 10.0.0.2/30 [Peer] PublicKey = --Publickey of Wireguard Server-- Endpoint = --Public IP of Wireguard Server>:51820-- AllowedIPs = 10.0.0.0/30
We’ve added the [Peer]
section to the config file, which is what will allow us to decrypt traffic coming from the Wireguard server that is sent back to us. We’ll have to do this for the server as well.
You can think of AllowedIPs
as the set of addresses you expect to be reachable on the other end of the connection. Your mask will inform how packets are filtered, so if you’re just doing a point-to-point connection, then a `/32` is just fine.
Add the peer to the server
Open the /etc/wireguard/wg0.conf
file on the Wireguard Server and add the public key of Client along with these options:
PrivateKey = --Private Key of Wireguard Server-- Address = 10.0.0.1/24 ListenPort = 51820 PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT [Peer] PublicKey = --Public key of Client-- AllowedIPs = 10.0.0.2/30
We’ve added the peer information for our intended connection, along with their public key, which we’ll need to decrypt the traffic they send to us.
5. Bring interfaces up and create services (Optional)
Now we’ll need to start the wireguard interfaces up on both peers. The command will be the same, but you should start the Wireguard Server first with:
wg-quick up wg0
Note: wg-quick
is a wrapper for a bunch of functions in wg. Turning off the interface can be done with wg-quick down wg0
If you’d rather have wireguard as a service that’s up on startup, you can use
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
You can check the status with sudo systemctl status wg-quick@wg0
Finally, check to see if you have a connection with:
sudo wg show