Candid photograph of a Linux server terminal with a soft olive-green glow against a dark slate background, conveying a calm technical atmosphere.

Step-by-step guides for system administrators — covering command-line basics, web server setup, and preparation material for technical interviews.

Browse Tutorials

Building a WireGuard VPN server on RHEL for secure access

When you work from a café in Brisbane or run a small studio in Adelaide, exposing services over the public internet quickly becomes a pain. A modern encrypted tunnel gives you a private route back to your own machine, and WireGuard has become the go-to choice for sysadmins who want something lean, fast, and easy to audit. Its codebase is small enough to read in a sitting, and the cryptography it uses reflects current best practice rather than the legacy baggage carried by older protocols.

RHEL, along with its close relatives CentOS Stream, Rocky Linux, and Fedora Server, ships the kernel module out of the box on supported releases, so getting a tunnel running does not require a third-party repository on most installs. The steps below assume a freshly provisioned instance running RHEL 9 or later, with sudo access and a public IP address. If you are on the NBN at home and want to expose the tunnel to the wider world, you will also need to forward a single UDP port on your router.

Before touching any configuration, it is worth taking a moment to plan your addressing scheme, decide which clients will connect, and check whether your hosting provider places any restrictions on encrypted traffic. Australian providers such as Telstra, Optus, and the various smaller ISPs all log connection metadata under the data retention scheme, so running your own tunnel is as much about personal privacy as it is about reaching internal services. The Linuxtpoint site has plenty of background reading if you need a refresher on the underlying networking concepts.

Installing the WireGuard package and loading the kernel module

The first practical step is to install the userspace tooling and confirm the kernel module is available. On RHEL-family distributions, the package is simply called wireguard-tools, and the matching kmod-wireguard package handles the module load for kernels that already include the source.

sudo dnf install epel-release elrepo-release
sudo dnf install kmod-wireguard wireguard-tools

Once the install finishes, load the module and verify it has registered cleanly:

sudo modprobe wireguard
lsmod | grep wireguard

You should see the module listed with no error output. On a minimal cloud image, the headers package is sometimes missing, and modprobe will refuse to load the module until kernel-devel matches the running kernel. A quick uname -r followed by sudo dnf install kernel-devel-$(uname -r) usually fixes the mismatch. After confirming everything is in place, persist the module across reboots by creating a simple wireguard.conf file under /etc/modules-load.d/.

Generating the server key pair

WireGuard relies on standard Curve25519 key pairs for authentication. Generating them takes a single command, and the private key never has to leave the host that creates it. Move into a directory that the root user owns, because the private key must be kept readable only by root.

wg genkey | sudo tee /etc/wireguard/server_private.key
sudo cat /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
sudo chmod 600 /etc/wireguard/server_private.key

Treat both files as secrets. The private key is the credential that proves the server is who it claims to be, and the public key is what every client uses to verify it. If you are scripting this on a fleet of machines spread across Australian data centres in Sydney, Melbourne, and Perth, use a configuration management tool rather than copying keys around by hand.

Writing the server configuration

The configuration file lives at /etc/wireguard/wg0.conf by convention, and the filename also controls the interface name. Pick a port that is unlikely to be filtered by your hosting provider, with 51820 being the default and usually a safe bet.

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>
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

The Address line sets the tunnel subnet; a private range keeps it isolated from your existing LAN. The PostUp and PostDown directives handle the NAT rules so that traffic from clients appears to originate from the server's public IP, which matters when you want to reach geo-restricted services such as Kayo Sports or ABC iView while travelling overseas.

Enabling IP forwarding and opening the firewall

A tunnel that cannot route packets is just an expensive way to type commands at a remote shell. RHEL ships with packet forwarding disabled by default, so enable it through sysctl and make the change survive a reboot.

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard-forward.conf

Next, open the WireGuard listening port in firewalld, which is the default firewall manager on RHEL.

sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload

If you also want to allow other services through firewalld once clients are connected, add the wg0 interface to the trusted zone. From a regional perspective, this matters more than it might seem: an NBN connection in regional Queensland can drop packets under load, and a misconfigured firewall rule is often the first place to look when connections stall at the handshake stage.

Adding a peer for each client

Every client that connects to the server needs its own key pair and an entry in the server configuration under a [Peer] block. Generate the keys on the client device if possible, then add the public key to the server and assign a unique tunnel IP.

[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.0.0.2/32

The AllowedIPs field acts as a simple ACL, telling the server to only accept traffic from that tunnel address. Repeat the block for every device you want to allow, incrementing the final octet. If you manage a handful of remote staff across Australia and New Zealand, a small spreadsheet of keys and IP assignments saves a lot of confusion later.

On the client side, create a matching wg0.conf with the server's public key, the endpoint address, and the same AllowedIPs set to 0.0.0.0/0 if you want a full tunnel.

Verifying the handshake and throughput

Bring the server interface up with sudo wg-quick up wg0 and enable the systemd unit so it starts on boot.

sudo systemctl enable --now wg-quick@wg0
sudo wg show

A few commands worth keeping in muscle memory when checking on a live tunnel:

The handshake timestamp, measured in seconds, is the clearest signal that the tunnel is healthy. From a Sydney datacentre, you can typically see a handshake within a couple of hundred milliseconds; from Perth to Sydney, the round-trip time is closer to fifty milliseconds, and anything well above a second deserves a closer look. For a quick throughput check, run iperf3 between the server and a connected client to confirm the link is delivering the bandwidth you expect.

Common pitfalls and maintenance habits

A few recurring issues show up often enough to deserve their own checklist. Keep this in mind when something does not work the first time:

A small habit that pays off is running wg show from a cron job and alerting on stale handshakes. If you are the only operator and you happen to be in the middle of a long arvo at the cricket, an automated alert will tell you the tunnel is down before a colleague does.

For more guides on the broader Linux ecosystem, the myeasyprojects tracker has a useful collection of side utilities worth bookmarking. Readers who want a refresher on the assumptions behind the configuration choices above can also check the about page for background on the publication.

The thing to carry away from all of this is that WireGuard on RHEL is genuinely small once you strip away the surrounding network plumbing. A working tunnel comes down to a key pair, a configuration file, packet forwarding, and a single UDP port that is reachable from the clients you care about. Get those four pieces right, and you have a private route into your own network that holds up well against both casual surveillance and the more demanding traffic patterns of a remote-first Australian workplace.