WireGuard is a modern, high-performance VPN that uses state-of-the-art cryptography. It runs as a kernel module, which makes it faster than userspace VPN solutions like OpenVPN. WireGuard is simple to configure, uses minimal code (around 4,000 lines), and establishes connections using public/private key pairs – similar to SSH.
This guide walks through installing and configuring WireGuard VPN on Rocky Linux 10 and AlmaLinux 10. We cover server setup, key generation, firewall rules, IP forwarding, SELinux, client configuration, and adding multiple clients.
Prerequisites
- A server running Rocky Linux 10 or AlmaLinux 10 with root or sudo access (this is the VPN server)
- A client machine (Linux, macOS, Windows, or mobile) to connect to the VPN
- A static IP address configured on the VPN server
- UDP port 51820 open on any upstream firewall or cloud security group
Step 1: Install WireGuard on Rocky Linux 10 / AlmaLinux 10
WireGuard kernel module is included in the Linux kernel since version 5.6. Rocky Linux 10 and AlmaLinux 10 ship with kernel 6.x, so the module is already available. You only need to install the wireguard-tools userspace package.
Install the EPEL repository first, then install wireguard-tools:
sudo dnf install epel-release -y
Now install the WireGuard tools package:
sudo dnf install wireguard-tools -y
Verify the installation by checking the wg command version:
wg --version
You should see the WireGuard tools version printed:
wireguard-tools v1.0.20210914 - https://git.zx2c4.com/wireguard-tools/
Confirm the WireGuard kernel module is available:
sudo modprobe wireguard
lsmod | grep wireguard
The output confirms the WireGuard kernel module is loaded:
wireguard 98304 0
curve25519_x86_64 36864 1 wireguard
libchacha20poly1305 16384 1 wireguard
ip6_udp_tunnel 16384 1 wireguard
udp_tunnel 32768 1 wireguard
Step 2: Generate WireGuard Server Keys
WireGuard uses public/private key pairs for authentication. Generate the server key pair in the /etc/wireguard/ directory with restrictive permissions.
Set the umask and generate the private key:
wg genkey | sudo tee /etc/wireguard/server_private.key
Lock down the private key file permissions:
sudo chmod 600 /etc/wireguard/server_private.key
Derive the public key from the private key:
sudo cat /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
View both keys – you will need the public key when configuring clients:
cat /etc/wireguard/server_private.key
cat /etc/wireguard/server_public.key
Each key is a base64-encoded string. Keep the private key secret – never share it.
Step 3: Configure WireGuard VPN Server
Create the WireGuard server configuration file. Open the config file for editing:
sudo vi /etc/wireguard/wg0.conf
Add the following configuration, replacing SERVER_PRIVATE_KEY with the contents of /etc/wireguard/server_private.key:
[Interface]
# VPN subnet - the server gets .1
Address = 10.10.10.1/24
# WireGuard listening port
ListenPort = 51820
# Server's private key
PrivateKey = SERVER_PRIVATE_KEY
# Save peer changes at shutdown
SaveConfig = false
Set proper permissions on the config file:
sudo chmod 600 /etc/wireguard/wg0.conf
Step 4: Enable IP Forwarding
IP forwarding allows the VPN server to route traffic between clients and the internet. Without it, clients can connect but cannot reach anything beyond the server itself.
Enable IPv4 forwarding persistently:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-wireguard.conf
If you also want IPv6 forwarding through the VPN:
echo "net.ipv6.conf.all.forwarding = 1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
Apply the settings immediately:
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
Verify that forwarding is enabled:
sysctl net.ipv4.ip_forward
The output should confirm forwarding is active:
net.ipv4.ip_forward = 1
Step 5: Configure Firewall for WireGuard
Rocky Linux 10 and AlmaLinux 10 use firewalld by default. Open UDP port 51820 for WireGuard and enable masquerading so VPN clients can access the internet through the server.
Open the WireGuard port:
sudo firewall-cmd --add-port=51820/udp --permanent
Enable masquerading (NAT) for VPN traffic:
sudo firewall-cmd --add-masquerade --permanent
Reload firewalld to apply the changes:
sudo firewall-cmd --reload
Verify the firewall rules are active:
sudo firewall-cmd --list-all
You should see port 51820/udp in the ports list and masquerade: yes in the output:
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: cockpit dhcpv6-client ssh
ports: 51820/udp
protocols:
forward: yes
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
Step 6: Handle SELinux for WireGuard
SELinux is enforcing by default on Rocky Linux 10 and AlmaLinux 10. WireGuard works under SELinux without issues in most cases because it runs as a kernel module. However, if you encounter SELinux denials when starting the WireGuard service, check the audit log:
sudo ausearch -m avc -ts recent
If there are denials related to WireGuard, generate and apply a custom policy module:
sudo ausearch -m avc -ts recent | audit2allow -M wireguard_custom
sudo semodule -i wireguard_custom.pp
Verify the current SELinux status:
getenforce
The output should show Enforcing – never disable SELinux to work around WireGuard issues.
Step 7: Start and Enable WireGuard VPN Service
Start the WireGuard interface using systemd and enable it to start at boot:
sudo systemctl enable --now wg-quick@wg0
Check that the service is running:
sudo systemctl status wg-quick@wg0
The service should show active (exited) – this is normal because WireGuard runs in the kernel, not as a long-running daemon:
● [email protected] - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled; preset: disabled)
Active: active (exited)
Docs: man:wg-quick(8)
man:wg(8)
https://www.wireguard.com/
Verify the WireGuard interface is up with wg show:
sudo wg show
The output shows the server interface details including its public key and listening port:
interface: wg0
public key: aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcdefg=
private key: (hidden)
listening port: 51820
You can also verify the interface IP address:
ip addr show wg0
The output confirms the WireGuard tunnel interface has the configured VPN address:
4: wg0: mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.10.10.1/24 scope global wg0
valid_lft forever preferred_lft forever
Step 8: Configure WireGuard VPN Client
On the client machine, install WireGuard and generate a key pair. These steps work on any Linux distribution. For Rocky Linux 10 / AlmaLinux 10 clients:
sudo dnf install epel-release -y
sudo dnf install wireguard-tools -y
Generate the client key pair:
wg genkey | sudo tee /etc/wireguard/client_private.key
sudo chmod 600 /etc/wireguard/client_private.key
sudo cat /etc/wireguard/client_private.key | wg pubkey | sudo tee /etc/wireguard/client_public.key
Create the client WireGuard configuration file:
sudo vi /etc/wireguard/wg0.conf
Add the following configuration. Replace the placeholder values with your actual keys and server IP:
[Interface]
# Client's private key
PrivateKey = CLIENT_PRIVATE_KEY
# Client VPN IP address
Address = 10.10.10.2/24
# DNS server for VPN traffic
DNS = 1.1.1.1, 8.8.8.8
[Peer]
# Server's public key
PublicKey = SERVER_PUBLIC_KEY
# Server public IP and WireGuard port
Endpoint = 192.168.1.100:51820
# Route all traffic through VPN (full tunnel)
# Use 10.10.10.0/24 for split tunnel (VPN subnet only)
AllowedIPs = 0.0.0.0/0
# Keep connection alive behind NAT
PersistentKeepalive = 25
Set proper permissions on the client config:
sudo chmod 600 /etc/wireguard/wg0.conf
Step 9: Add Client Peer to the Server
Back on the VPN server, add the client as a peer. You need the client’s public key (from /etc/wireguard/client_public.key on the client machine).
Add the peer to the server’s running WireGuard interface:
sudo wg set wg0 peer CLIENT_PUBLIC_KEY allowed-ips 10.10.10.2/32
To make this persistent across reboots, add the peer to the server config file. Open the server config:
sudo vi /etc/wireguard/wg0.conf
Append the peer block below the [Interface] section:
[Peer]
# Client 1
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32
Step 10: Connect the Client and Verify
On the client machine, start the WireGuard connection:
sudo wg-quick up wg0
The output shows the interface being created and routes added:
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.10.10.2/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
Verify the connection from the client by running wg show:
sudo wg show
A successful connection shows a recent handshake timestamp and data transfer stats:
interface: wg0
public key: xYzAbCdEfGhIjKlMnOpQrStUvWxYz1234567890abc=
private key: (hidden)
listening port: 48921
fwmark: 0xca6c
peer: aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890abcdefg=
endpoint: 192.168.1.100:51820
allowed ips: 0.0.0.0/0
latest handshake: 5 seconds ago
transfer: 1.24 KiB received, 1.48 KiB sent
persistent keepalive: every 25 seconds
Test connectivity by pinging the server’s VPN address from the client:
ping -c 3 10.10.10.1
Successful pings confirm the VPN tunnel is working:
PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.
64 bytes from 10.10.10.1: icmp_seq=1 ttl=64 time=1.23 ms
64 bytes from 10.10.10.1: icmp_seq=2 ttl=64 time=0.98 ms
64 bytes from 10.10.10.1: icmp_seq=3 ttl=64 time=1.05 ms
--- 10.10.10.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.980/1.086/1.230/0.104 ms
To enable the client connection at boot:
sudo systemctl enable --now wg-quick@wg0
Adding Multiple WireGuard Clients
Each client needs its own key pair and unique VPN IP address. For a second client, generate keys on the client machine and add a new [Peer] block to the server config. If you manage many clients, consider using Ansible to automate WireGuard deployments.
On the server, open the WireGuard config:
sudo vi /etc/wireguard/wg0.conf
Add additional peer blocks with unique IPs for each client:
[Peer]
# Client 2
PublicKey = CLIENT2_PUBLIC_KEY
AllowedIPs = 10.10.10.3/32
[Peer]
# Client 3
PublicKey = CLIENT3_PUBLIC_KEY
AllowedIPs = 10.10.10.4/32
After modifying the config file, restart the WireGuard service to load the new peers:
sudo systemctl restart wg-quick@wg0
Verify all peers are registered:
sudo wg show wg0
The output lists all configured peers with their public keys and allowed IPs.
WireGuard VPN Quick Reference
| Command | Description |
|---|---|
sudo wg show | Show WireGuard interface status and peers |
sudo wg-quick up wg0 | Bring up the WireGuard interface |
sudo wg-quick down wg0 | Bring down the WireGuard interface |
sudo systemctl restart wg-quick@wg0 | Restart the WireGuard service |
sudo wg set wg0 peer KEY allowed-ips IP | Add a peer to the running interface |
sudo wg set wg0 peer KEY remove | Remove a peer from the running interface |
wg genkey | Generate a new private key |
wg pubkey | Derive a public key from a private key |
Conclusion
WireGuard VPN is running on Rocky Linux 10 / AlmaLinux 10 with firewall rules, IP forwarding, and SELinux handled. Clients can connect using their generated key pairs and route traffic through the VPN server. For more VPN options, see WireGuard VPN on Ubuntu or WireGuard on Amazon Linux. For the official installation guide covering all platforms, see the WireGuard installation documentation.
For production use, consider restricting AllowedIPs to specific subnets instead of 0.0.0.0/0, implementing DNS-based ad blocking through the VPN, and monitoring peer connections with periodic wg show checks.