AlmaLinux

Configure WireGuard VPN on Rocky Linux 10 / AlmaLinux 10

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

CommandDescription
sudo wg showShow WireGuard interface status and peers
sudo wg-quick up wg0Bring up the WireGuard interface
sudo wg-quick down wg0Bring down the WireGuard interface
sudo systemctl restart wg-quick@wg0Restart the WireGuard service
sudo wg set wg0 peer KEY allowed-ips IPAdd a peer to the running interface
sudo wg set wg0 peer KEY removeRemove a peer from the running interface
wg genkeyGenerate a new private key
wg pubkeyDerive 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.

Related Articles

Openstack Installation of Three node OpenStack Queens Cluster – Part Seven Monitoring How to Monitor Linux Server with Netdata and Grafana Networking Using Rathole – Reverse proxy for NAT traversal on Linux AlmaLinux Install Xen Orchestra on Rocky / CentOS / AlmaLinux

Press ESC to close