Setting up a WireGuard VPN for Remote Access

post-thumb
post-thumb

What is WireGuard?

WireGuard is a VPN, which tunnels traffic over encrypted, secure UDP packet streams. Once a tunnel is established, the endpoints are allowed to roam (change IP addresses, such as might happen switching between WiFi networks or when connected to a cell tower). It is special when compared to other VPN technologies for many technical reasons, which led to its rapid adoption into the Linux Kernel, but three features in particular make WireGuard stand out: the CryptoKey Routing Table, the way public/private keypairs are handled, and the “silent by default” behavior.

According to the wireguard website,

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.

WireGuard Basics

Unlike traditional VPN technologies, WireGuard has no concept of Client or Server, but instead all nodes on the network are simply Peers, connecting Point-to-Point. This allows for some really interesting scenarios where packets sent through the VPN can be sent through very specific routes by setting IP masks appropriately, and if all Peers on the VPN have public IP addresses (or else they can ‘see’ each other in some other way, perhaps by sharing an insecure local network), the single point of failure built into the Hub-and-Spoke model becomes optional.

Hub and Spoke vs. P2P

However, even if WireGuard doesn’t specifically recognize the Hub and Spoke model, it’s still a valid configuration,and we’ll be using it for this tutorial. Let’s see how easy it is to configure a Hub and Spoke-style, simple WireGuard VPN ready for personal or commercial use.

Server Instructions

  1. Choose a private IP block to reserve. In order to use WireGuard inside of a Spoke and Hub paradigm, it’s necessary to reserve a block of IP addresses for all the nodes. (When running Peer to Peer, it’s not necessary for these addresses to share a subnet, as a CIDR of /32 can be used for each peer.) Private IP ranges include:

    • 10.0.0.0 to 10.255.255.255
    • 172.16.0.0 to 172.31.255.255
    • 192.168.0.0 to 192.168.255.255

    An example range for WireGuard might look like: 192.168.2.1-192.168.2.255 (be sure this range doesn’t conflict with that of your router). In CIDR notation, this range would be: 192.168.2.0/24. You can use a CIDR Calculator to determine the proper format for a given range.

  2. Choose a port for your tunneled traffic to use. WireGuard traffic flows over UDP, and by default uses port 51820. For this tutorial, we will assume you are using the default port, but if you are running multiple WireGuard VPNs on the same server, you will need to choose a different port for each one.

  3. Choose a cloud provider that provides you with a public IP address. My personal preference is Linode/Akamai (by using my signup link you’ll get free credits, as will I.)

  4. Once you are ready to spin up a server, be sure to choose a distribution/flavor which ships Linux 5.6 or above. (Some versions of Ubuntu with older kernels also received backports, but if you have the option, go with the latest stable release available.) It is possible to use WireGuard in Userspace (if you don’t know what this means, don’t worry about it, just use a newer installation image) but it is much slower than the version running in the kernel. Going forward, we will assume you have the public IP of 93.184.216.34 (used for example.com).

  5. Install WireGuard and its helper utilities. The name of the helper utilities package is usually wireguard-tools, and installing that package should bring in wireguard as well. If you don’t already have iptables installed, you will need to install that as well. (On Debian-based systems, run apt install wireguard-tools iptables.)

  6. Enable IP forwarding. This is a necessary step for the server to act as a router. On Linux, this is done by running sysctl -w net.ipv4.ip_forward=1. To make this change permanent, edit or create /etc/sysctl.conf and add the line net.ipv4.ip_forward=1.

  7. Create a keypair for your server. Once WireGuard is installed, you can generate a private key by running wg genkey. To get the public key, run wg pubkey and paste (or pipe) in the private key. This keypair is just like an SSH public/private keypair, so keep it safe!

  8. Use the keypairs to create a configuration file. The next step is to create a configuration file for your server. There are three main pieces of information required:

    • the interface and port to listen on
    • the WireGuard private IP and netmask (CIDR Notation) you are committing to use (such as 192.168.2.1/24)
    • the Private Key of your server

    Create a file at /etc/wireguard/my-vpn.conf and add in the following:

    [Interface]
    ListenPort = 51820
    PrivateKey = <SERVER PRIVATE KEY HERE> # <SERVER PUBLIC KEY HERE>
    Address = 192.168.2.1/24
    PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
    

    Many systems use eth0 as the name of the primary network interface, but if yours is different, you will need to change it in the PostUp and PostDown commands. If you are unsure of your default gateway’s interfacve name, run ip a and look for the interface with the public IP address you are using to connect to the server.

    Additionally, you will add a block for each Peer, but we’ll need to generate those keypairs first. More on that later.

  9. Be sure the connection port is exposed through your hosting provider (for UDP traffic). Instructions for Linode can be found here. You may need to consult your provider’s documentation for more information.

  10. Before we start up our server, we need some more information from our clients. We’ll come back to the server later.

Client Instructions

Linux instructions:
  1. Ensure your kernel has support for WireGuard, or install the userspace version. On Ubuntu/Debian-based systems, run apt install wireguard-tools
  2. Create the folder /etc/wireguard/
  3. Generate a new keypair the same way you did on the server: wg genkey
  4. Place the keypair into a config file named my-vpn.conf and save it, along with the details you got from the server. The format is as follows:
[Interface]
PrivateKey = <CLIENT PRIVATE KEY HERE> # <CLIENT PUBLIC KEY HERE>
Address = 192.168.2.4/24 # Or whatever IP you want your client to use on the VPN

[Peer]
PublicKey = <SERVER PUBLIC KEY HERE>
AllowedIPs = 192.168.2.0/24 # This is the subnet you chose for your VPN, and should match the server's
Endpoint = 93.184.216.34:51820 # This is the public IP of your server, and the port you chose
# Note you can also use a domain name, if you want:
# Endpoint = example.com:51820
PersistentKeepalive = 25 # allow your client to roam without dropping the connection
  1. chmod the config file and the /etc/wireguard directory to 400 and chown it to root:root.
  2. On systemd-based systems, run systemctl enable wg-quick@my-vpn.
  3. Move on to the server section, when complete move on to the next step.
Mac instructions:
  1. Install Wireguard for Mac
  2. Follow prompts to fill in the info from your server.
  3. Choose an IP from the subnet you chose for your VPN.
  4. Save your Public Key for later.
  5. Enable start on demand.
  6. Complete the server steps next, before hitting Save.

Final Server Instructions

  1. Inside of your my-vpn.conf file, create a Peer block following the pattern of the previous entries:
    [Peer] # name of client
    PublicKey = <CLIENT PUBLIC KEY HERE>
    AllowedIPs = 192.168.2.<n>/32 # replace `<n>` with the last octet of the Client's WireGuard private IP
    
  2. Save and close the config file.
  3. Ensure the config file is owned by root and has permissions of 400.
  4. Run systemctl enable --now wg-quick@my-vpn to start the WireGuard tunnel and set it to start automatically on boot.
  5. Continue setting up from the client side.
Linux
  1. Same as for the server, run systemctl enable --now wg-quick@my-vpn

  2. Validate the VPN is running with wg. You should see something like this:

    interface: my-vpn
    public key: <CLIENT PUBLIC KEY HERE>
    private key: (hidden)
    listening port: 58341
    
    peer: <SERVER PUBLIC KEY HERE>
    endpoint: 93.184.216.34:51820
    allowed ips: 192.168.2.0/24
    latest handshake: 13 seconds ago
    transfer: 5.37 MiB received, 6.40 MiB sent
    persistent keepalive: every 25 seconds
    
  3. If you see an error, check the logs with journalctl -u wg-quick@my-vpn.

MacOS
  1. Hit Save.
  2. Optionally, in your Mac’s System Preferences, go to Network and check the box for Enable VPN on Demand.

Next Steps

You should now have a working WireGuard VPN, ready for roaming and personal use. There’s only one client for now, but you can add as many as you like by repeating the client steps on each new device. (Be sure to pick a unique private IP address inside of the subnet you chose for your VPN for each client.) Then, you can jump directly from one client to another using the WireGuard private IP addresses. This can be particularly useful when pairing the WireGuard app for Android with Termux or JuiceSSH to access your laptop or desktop on the go.

Once the client side setup is done, simply add a Peer block for each client in the server’s config file, using a unique private IP address, then run systemctl restart wg-quick@my-vpn on the server to restart the tunnel with the new configuration. It is normal for the tunnel to drop when you run the restart command, but it should come back up within a few seconds.

If you have any issues, check the logs with journalctl -u wg-quick@my-vpn. If you’re stumped, feel free to reach out to the community in my Discord, and someone may be able to help you out.

Going Further

If you want to take your WireGuard VPN to the next level, you can add a DNS server to your server’s config file, and then add a DNS entry to each client’s Interface block. You can read more about that here.

It’s possible to use WireGuard to route all of your traffic through the VPN, pair WireGuard with netns or Docker containers to force applications to use the VPN, or even use WireGuard to create a mesh network. I’ll likely be writing more about these topics in the future. For now, there are great resources available on the WireGuard website and on YouTube.

“WireGuard” and the “WireGuard” logo are registered trademarks of Jason A. Donenfeld.

You May Also Like