Talk Tech to Me: Configuring WireGuard: The Hottest New VPN Technology

WireGuard is a cross-platform VPN that minimizes bandwidth and maximizes data transfer speed with top-notch security and a lower attack surface.
Talk Tech to Me, brought to you by CompTIA

Configuring secure access to servers and networks across the internet for remote workers is crucial to ensure that systems and data remain secure. Whether you are a server administrator, network administrator or cybersecurity professional, the method you’ll likely use to provide this secure access is via a virtual private network (VPN).

In this article, I’ll describe how to configure WireGuard VPN technology using Fedora Linux – leveraging skills from CompTIA Network+, CompTIA Linux+, CompTIA Server+ and CompTIA Security+.

Why WireGuard?

When it comes to encrypting traffic between systems, there’s a wide variety of different VPN software available, some of which have been used since the 1990s. Each of them focus on different encryption algorithms and flow control strategies, alongside mechanisms for providing for secure authentication and negotiating encryption keys. Unfortunately, this complexity often translates to more problems, slower traffic, as well as fewer use cases and supported operating systems.

WireGuard uses high-performance strong cryptography, such as ChaCha20 (for symmetric data encryption) and Curve25519 (for asymmetric key negotiation), alongside a framework similar to Secure Shell (SSH) and Git. Moreover, it provides VPN functionality only when traffic is sent, doesn't include complex authentication mechanisms and is available for all desktop and mobile operating systems.

In short, WireGuard is a cross-platform VPN that minimizes bandwidth and maximizes data transfer speed while boasting top-notch security and a lower attack surface.

Basic VPN Configuration

Like its name suggests, a VPN is a virtual network that overlays your ordinary network. When data is sent on this virtual network, it is automatically encrypted to ensure that the data remains private.  We often say that this data is tunneled through the VPN.

WireGuard does not have a separate client and server component. Each system that participates in a WireGuard VPN is considered equal and called a peer in WireGuard documentation. However, it's easier to visualize communication when we think in terms of clients and servers, so we'll call one system a client and the other a server. And while WireGuard works equally well with IPv4 or IPv6 networks, we’ll stick to IPv4 for readability.

The following diagram shows a client (IP address 192.168.1.107) and server (IP address 192.168.1.106) connected to the same IPv4 local area network (LAN) (192.168.1.0/24). After creating a VPN, each system will have a second IP address on the VPN (e.g., 172.16.0.1 for the client and 172.16.0.99 for the server).

In the following sections, we'll implement this basic VPN configuration using WireGuard, and then discuss the configuration for other use cases.

A diagram of VPN configuration using WireGuard

Installing WireGuard

Visit https://www.wireguard.com/install/ to see how to install WireGuard on your operating system.

You can usually install WireGuard from your Linux or BSD UNIX repository. For Windows, Android, macOS and iOS, there is an app you can get, but you should avoid the macOS app and instead use the Homebrew package manager method. (The macOS app is problematic at the time of this writing.) Since the client and server I use run Fedora Linux, I ran the dnf install wireguard-tools command as root (or via sudo) to install WireGuard on them.

Configuring WireGuard

The first step for configuring WireGuard is to generate an asymmetric public/private key pair on each system that will participate in WireGuard. To generate and save the private key to the file privatekey, as well as generate and save the associated public key to the file publickey and view the results, you can run the following commands on both your server and client:

[root@server ~]# wg genkey | tee privatekey | wg pubkey > publickey

[root@server ~]# cat privatekey

+FqYdSx+rIg2gwwyd3hCfap/1Vz3z2UuRZCPKKwMaXw=

[root@server ~]# cat publickey

cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

[root@client ~]# wg genkey | tee privatekey | wg pubkey > publickey

[root@client ~]# cat privatekey

0EQpGsSfGwVRdxcCywG2ymnLG7mjmv+rB02UodcH10k=

[root@client ~]# cat publickey

8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

Next, you must construct a WireGuard interface on each system that has a virtual private IP address and port number of your choice. The first WireGuard interface is called wg0, and should use the private key you generated and saved to the privatekey file earlier (you don't need to specify the public key as WireGuard will automatically generate it from the private key).

To configure a new wg0 interface on the server that listens on port 55234 using the virtual private IP 172.16.0.99 and view the results, you can run the following commands:

[root@server ~]# ip link add wg0 type wireguard

[root@server ~]# ip addr add 172.16.0.99/24 dev wg0

[root@server ~]# wg set wg0 private-key ./privatekey listen-port 55234

[root@server ~]# ip link set wg0 up

[root@server ~]# wg

interface: wg0

  public key: cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

  private key: (hidden)

  listening port: 55234

To configure a new wg0 interface on the client that listens on port 55123 using the virtual private IP 172.16.0.1 and view the results, you can run the following commands:

[root@client ~]# ip link add wg0 type wireguard

[root@client ~]# ip addr add 172.16.0.1/24 dev wg0

[root@client ~]# wg set wg0 private-key ./privatekey listen-port 55123

[root@client ~]# ip link set wg0 up

[root@client ~]# wg

interface: wg0

  public key: 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

  private key: (hidden)

  listening port: 55123

Now that you have a wg0 interface on both systems, you must add the client's public key, IP and port number on the server, as well as add the server's public key, IP and port number on the client in order to allow the systems to identify and communicate with each other.

You must also specify the IP addresses or networks you will allow over WireGuard. You can do all of this with one (long) command on each system:

[root@server ~]# wg set wg0 peer 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE= allowed-ips 172.16.0.0/16 endpoint 192.168.1.107:55123

[root@client ~]# wg set wg0 peer cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs= allowed-ips 172.16.0.0/16 endpoint 192.168.1.106:55234

The allowed-ips 172.16.0.0/16 argument in these commands is important to note. When WireGuard is sending information to the other system, 172.16.0.0/16 is treated like a target route. In other words, if your system sends data to the 172.16.0.0/16 network, it triggers WireGuard to start the VPN. However, when receiving information from the other system, 172.16.0.0/16 is treated like an access control list. In other words, your system won't accept VPN traffic unless it originates from the 172.16.0.0/16 network.

That's it, you now have WireGuard ready to go! Let's ping the virtual private IP of the server (172.16.0.99) from the client and view the output of wg on both systems:

[root@client ~]# ping 172.16.0.99

<output omitted>

[root@client ~]# wg

interface: wg0

   public key: 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

   private key: (hidden)

   listening port: 55123

peer: cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

   endpoint: 192.168.1.106:55234

   allowed ips: 172.16.0.0/16

   latest handshake: 18 seconds ago

   transfer: 8.21 KiB received, 15.10 KiB sent

[root@server ~]# wg

interface: wg0

   public key: cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

   private key: (hidden)

   listening port: 55192

peer: 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

   endpoint: 192.168.1.107:51423

   allowed ips: 172.16.0.0/16

   latest handshake: 27 seconds ago

   transfer: 7.01 KiB received, 11.39 KiB sent

Making WireGuard Configuration Persistent

When you reboot, your wg0 interface and WireGuard configuration is gone. All that is left are your privatekey and publickey files. Thus, you would need to repeat the same commands on both systems again to set up the same WireGuard VPN.

For organizations that use infrastructure as code (IaC), the necessary commands and keys could be placed in their automation software (e.g., Ansible) or continuous deployment (CD) orchestration software (e.g., Kubernetes). Alternatively, you could place these commands within a shell script and configure your system to execute it at boot time.

Since the private and public keys are already generated, you could create the following BASH shell script on the client, for example:

[root@client ~]# cat wireguard-client.sh

#!/bin/bash

ip link add wg0 type wireguard

ip addr add 172.16.0.1/16 dev wg0

wg set wg0 private-key ./privatekey listen-port 55123

ip link set wg0 up

wg set wg0 peer cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs= allowed-ips 172.16.0.0/16 endpoint 192.168.1.106:55234

However, a better method for making your WireGuard configuration persistent is to generate a WireGuard configuration file from wg0 and save it to the /etc/wireguard/wg0.conf file. You'll also need to copy your privatekey and publickey files to the same directory and ensure that only root has read and write permission to the contents of the /etc/wireguard/ directory.

To do this on the client, and view the results, you can run the following commands:

[root@client ~]# wg showconf wg0 > /etc/wireguard/wg0.conf

[root@client ~]# cp *key /etc/wireguard/

[root@client ~]# chmod 600 /etc/wireguard/*

[root@client ~]# cat /etc/wireguard/wg0.conf

  [Interface]

  Address = 172.16.0.1/16

  ListenPort = 55123

  PrivateKey = 0EQpGsSfGwVRdxcCywG2ymnLG7mjmv+rB02UodcH10k=

  [Peer]

  PublicKey = cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

  AllowedIPs = 172.16.0.0/16

  Endpoint = 192.168.1.106:55234

After creating /etc/wireguard/wg0.conf, you can use the wg-quick up wg0 and wg-quick down wg0 commands to activate and deactivate wg0, or set your system to automatically activate wg0 at boot time using systemctl enable [email protected].

You can connect multiple clients to the same server. In this case, the server will need to know the PublicKey, IP and port for each client, so you will have multiple [Peer] sections in the /etc/wireguard/wg0.conf file on the server, one for each client. After adding a new [Peer] section to this file, you must run the wg-quick down wg0 ; wg-quick up wg0 command on the server to activate the new configuration.

Using WireGuard for Remote Access to a Network

While having a VPN between a client and a server allows for encrypted communication between them, the most common use case for a VPN is to encrypt communication between a client and a network (typically a corporate network). In this case, the server functions as a router on this target network, and will route packets from the client to the target network after decrypting them.

To ensure that all client traffic is forwarded to the server across the VPN, the client uses the VPN as their default gateway route. Moreover, if the resource the client requests is not on the corporate network, then the server will use its own default gateway route to send the traffic out the corporate internet connection.

This use case is called remote access (or site access), and allows a client to securely access the resources on a corporate network from across the internet as if their system was physically located on it.

The configuration of a remote access VPN depends on the structure of your target network. A sample network is shown below. Both home and corporate LANs connect to the internet via their internet service provider (ISP).

On the corporate side, the ISP often provides a demarcation point (demarc) router that provides a public IP address to a next generation firewall (NGFW). In addition to providing security functionality, the NGFW is often configured as a network address translation (NAT) router to allow corporate LANs to access the internet using private IP address ranges, such as the 10.0.x.0/24 networks shown below for the screened subnet zone, as well as the department LANs that connect to that subnet using a regular router.

The client shown below also has a private IP address (192.168.1.107) because it's usually on a home network behind a NAT router as well.

A diagram of VPN configuration using WireGuard

There are two main configuration methods for remote access, depending on whether the WireGuard server is located behind the NGFW, or directly connected to the demarc. 

Method 1: Remote Access Using a WireGuard Server Behind a NGFW

In the configuration shown below, the WireGuard server (10.0.0.99) is located on the private 10.0.0.0/24 network behind the NGFW.

A diagram of VPN configuration using WireGuard

Thus, when configuring WireGuard on the client (192.168.1.107), you would specify endpoint publicIP, where publicIP is the public IP address of the NGFW visible across the internet. The NGFW must also be configured to accept WireGuard traffic on the port you specify and forward it internally to the server (10.0.0.99) using standard port forwarding or reverse proxy. 

To force all client traffic to the server using WireGuard, you would specify allowed-ips 0.0.0.0/0 in the WireGuard configuration on the client (but still use allowed-ips 172.16.0.0/16 in the WireGuard configuration on the server). Any internet requests sent to the server from the client on the VPN will be forwarded to the server's default gateway (the NGFW) for relay to the internet. Responses received by the server will then be sent to the client on the VPN.

Since the client is behind a NAT router (e.g., on a home network) and not directly visible to the server across the internet, there is also no need to include the listen-port 55123 configuration on the client, nor the endpoint 192.168.1.107:55123 on the server. When the client contacts the server using WireGuard, the server will reply to the public IP address on the NAT router the client is behind.

Finally, to allow the server to forward IPv4 requests it receives from the client to other LANs, you must perform the following tasks on the server:

  • Turn on IP routing using the command: sysctl -w net.ipv4.ip_forward=1 >> /etc/sysctl.conf
  • Enable IP masquerading for requests from wg0 on the physical network interface connected to the DMZ LAN (e.g. eth0) using the command: iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Of course, all of this configuration could also be added to /etc/wireguard/wg0.conf on the client and server:

[root@client ~]# cat /etc/wireguard/wg0.conf

  [Interface]

  PrivateKey = 0EQpGsSfGwVRdxcCywG2ymnLG7mjmv+rB02UodcH10k=

  Address = 172.16.0.1/16

  #No ListenPort needed!

  [Peer]

  PublicKey = cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

  AllowedIPs = 0.0.0.0/0   #Forwards all traffic to this peer

  Endpoint = publicIP:55234

[root@server ~]# cat /etc/wireguard/wg0.conf

  [Interface]

  PrivateKey = +FqYdSx+rIg2gwwyd3hCfap/1Vz3z2UuRZCPKKwMaXw=

  Address = 172.16.0.99/16

  ListenPort = 55234

  PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A     

           POSTROUTING -o eth0 -j MASQUERADE

  PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D

             POSTROUTING -o eth0 -j MASQUERADE

  [Peer]

  PublicKey = 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

  AllowedIPs = 172.16.0.0/16

  #No Endpoint needed!

Method 2: Remote Access Using a WireGuard Server Connected to the Demarc

In the configuration shown below, the WireGuard server is connected directly to the demarc and obtains a public IP address, but has a second network interface connected to the DMZ (10.0.0.99). In this case, we call the WireGuard server an edge device as it sits on the edge of the corporate network.

A diagram of VPN configuration using WireGuard

The biggest difference between this configuration and the previous one is that when configuring WireGuard on the client (192.168.1.107), you would specify endpoint publicIP, where publicIP is the public IP address of the server connected to the demarc. Consequently, there's no need to configure the NGFW to forward requests to 10.0.0.99.

All other configuration is identical to the previous example. However, recall that you must specify the network interface that is connected to the DMZ when configuring IP masquerading on the server. If this network is eth1 (since eth0 is connected to the demarc), you would need to run the iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE command on the server.

Using WireGuard to Secure Traffic Between Two (Or More) Networks

If you have WireGuard servers configured as edge devices in two (or more) locations, and each location uses unique private IP ranges (e.g., 10.1.x.0/24 and 10.2.x.0/24), you could use WireGuard to allow systems on the 10.1.x.0/24 networks to securely access the systems on the 10.2.x.0/24 networks, and vice versa. This is often called a site-to-site VPN.

A diagram of VPN configuration using WireGuard

The configuration would be very similar to our basic example at the beginning of this article. Instead of a client and a server, we could have server1 and server2, and each server would be configured as a router that performs masquerading.

The /etc/wireguard/wg0.conf configuration for these systems is shown below:

[root@server1 ~]# cat /etc/wireguard/wg0.conf

  [Interface]

  PrivateKey = 0EQpGsSfGwVRdxcCywG2ymnLG7mjmv+rB02UodcH10k=

  Address = 172.16.1.99/16

  ListenPort = 55123

  PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A

           POSTROUTING -o eth1 -j MASQUERADE

  PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D

             POSTROUTING -o eth1 -j MASQUERADE

  [Peer]

  PublicKey = cjmyZf4c+6U3pD2QT+6Bxkjj9qzU8EePjc8dSeuXvWs=

  AllowedIPs = 10.2.0.0/16   #Forwards 10.2.x.0/24 traffic to server2

  Endpoint = server2publicIP:55234

  [root@server2 ~]# cat /etc/wireguard/wg0.conf

  [Interface]

  PrivateKey = +FqYdSx+rIg2gwwyd3hCfap/1Vz3z2UuRZCPKKwMaXw=

  Address = 172.16.2.99/16

  ListenPort = 55234

  PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A

           POSTROUTING -o eth1 -j MASQUERADE

  PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D

             POSTROUTING -o eth1 -j MASQUERADE

  [Peer]

  PublicKey = 8pfWwwPK8R+Qe/fuN5FZ0P2ddngWd8s79sOQw5Q7SXE=

  AllowedIPs = 10.1.0.0/16  #Forwards 10.1.x.0/24 traffic to server1

  Endpoint = server1publicIP:55123

It's also important to note that many NGFWs have site-to-site VPNs built into them. I imagine that most of them will move to using WireGuard for this functionality over time for performance and security reasons!

Get more tutorials like this right in your inbox with CompTIA’s IT Career Newsletter. Subscribe today, and you can save 10% off your next CompTIA purchase.

Email us at [email protected] for inquiries related to contributed articles, link building and other web content needs.

Read More from the CompTIA Blog

Leave a Comment