NetworkingWritten by GLWS16 min readUbuntu 24.04 LTS / AlmaLinux 9
Commands run on your server unless a section says otherwise. Replace example usernames, addresses and paths with your own values. Keep a working session open when changing remote access.

What WireGuard gives you

WireGuard is a fast, small VPN built into the Linux kernel. With a VPS as the server, your laptop or phone can send its traffic through the server, which is useful on untrusted networks, or reach private services that listen only on the server. It uses one UDP port and key pairs instead of passwords.

Use it only for lawful purposes and in line with the acceptable use policy. Traffic leaving the VPS appears to come from the VPS address.

Install WireGuard

Ubuntu includes the tools. On AlmaLinux 9 the tools are in the EPEL repository and the kernel provides the module. Check the installation by printing the version.

Ubuntu only
sudo apt update
sudo apt install wireguard
AlmaLinux only
sudo dnf install epel-release
sudo dnf install wireguard-tools
Both systems
wg --version

Create keys

Each device has a private key that never leaves it and a public key you share. Generate the server pair now, in a folder only root can read. Generate the client pair on the client if you can. For a quick test you can create it on the server and move it securely, then delete it.

Both systems
sudo sh -c 'umask 077; mkdir -p /etc/wireguard; wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub'
sudo cat /etc/wireguard/server.pub
On the client (a Linux machine; on phones use the app)
umask 077; wg genkey | tee client.key | wg pubkey > client.pub; cat client.pub

Enable forwarding

The server must forward packets between the VPN and the internet. Turn that on permanently with a sysctl file, and find the name of your public network interface, which you need for the next step.

Both systems
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system | grep ip_forward
ip route get 1.1.1.1 | grep -o "dev [^ ]*"

Write the server configuration

This file gives the server the address 10.8.0.1 on the VPN and listens on UDP 51820. The PostUp and PostDown lines add and remove firewall rules for forwarding and NAT. Replace eth0 with the interface you found, and paste the keys. On AlmaLinux with firewalld, skip the iptables lines and use the firewalld commands in the next section.

Both systems
WAN_IF=$(ip -4 route get 1.1.1.1 | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1);exit}}')
test -n "$WAN_IF" || { echo "No IPv4 outbound interface found"; exit 1; }
sudo tee /etc/wireguard/wg0.conf >/dev/null <<EOF
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = $(sudo cat /etc/wireguard/server.key)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o $WAN_IF -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o $WAN_IF -j MASQUERADE

[Peer]
# laptop
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32
EOF
sudo chmod 600 /etc/wireguard/wg0.conf
On AlmaLinux remove the PostUp and PostDown lines before starting. firewalld handles forwarding with masquerade instead.

Open the firewall and start it

Allow UDP 51820. On Ubuntu with UFW, add the port. On AlmaLinux, open the port, turn on masquerade for the zone and put the VPN interface in the trusted zone. Then start the tunnel and enable it at boot.

Ubuntu only
sudo ufw allow 51820/udp
AlmaLinux only
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --permanent --add-masquerade
sudo firewall-cmd --permanent --zone=trusted --add-interface=wg0
sudo firewall-cmd --reload
Both systems
sudo systemctl enable --now wg-quick@wg0
sudo wg show

Configure the client

On the client create a configuration with its own private key, the server's public key and the server address. Setting AllowedIPs to 0.0.0.0/0, ::/0 sends all traffic through the VPN. Setting it to 10.8.0.0/24 sends only VPN traffic through it. On a phone, the official WireGuard app can import the same text or a QR code.

This example routes IPv4 only. Add ::/0 only after configuring IPv6 addresses, forwarding and firewall rules on both peers. Decide how your client handles IPv6 to prevent traffic bypassing an IPv4-only VPN.

Client file, for example wg0.conf
[Interface]
Address = 10.8.0.2/24
PrivateKey = CLIENT_PRIVATE_KEY
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Linux client
sudo wg-quick up ./wg0.conf
ping -c 3 10.8.0.1
curl https://ifconfig.me
RECORDED LAB OUTPUT · Debian 13
interface: wg-client
  allowed ips: 0.0.0.0/0
  latest handshake: 2 seconds ago
  transfer: 476 B received, 564 B sent
  persistent keepalive: every 25 seconds
Recorded connection from an isolated client namespace to a separate VPN VM. This is an IPv4 tunnel; IPv6 routing requires its own configuration.
The last command should print your VPS's public IP address when all traffic is routed through the VPN. IPv6 traffic is not routed through this server unless you also configure IPv6, so disable IPv6 on the client or check for leaks.

Add devices and troubleshoot

Each new device gets its own key pair, a unique VPN address and a [Peer] block on the server. Apply changes without disconnecting others by syncing the configuration. If there is no handshake, check that UDP 51820 is open at the host firewall and at any provider-level firewall, and that the public keys are not swapped.

Both systems
sudo wg-quick strip wg0 | sudo wg syncconf wg0 /dev/stdin
sudo wg show
sudo ss -lunp | grep 51820

Official documentation

These upstream references provide more detail on the commands and workflows in this guide.