In this tutorial, you will install WireGuard on Ubuntu 24.04, create a server and one client peer, enable IPv4 forwarding and NAT, route the client’s IPv4 internet traffic through the Raff VM, and verify the tunnel end to end.
WireGuard is a VPN protocol that creates an encrypted network interface between peers. In this full-tunnel setup, the client uses AllowedIPs = 0.0.0.0/0, so all client IPv4 traffic is routed through the WireGuard server. The server then forwards and masquerades that traffic through its public network interface.
Raff Technologies supports 3,000+ customers and 15,000+ VMs. A Raff Linux VM provides the public IPv4 address, Ubuntu environment, root-level networking control, 3 Gbps unmetered VM traffic, firewall controls, and private networking needed for this setup.
The original full-tunnel workflow was tested on a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. The routing, masquerading, AllowedIPs, and keepalive guidance in this revision was reviewed against current Ubuntu Server and WireGuard documentation on August 14, 2026.
IPv4 scope: This tutorial deliberately builds a full-tunnel VPN for IPv4. If the client has working IPv6, IPv6 traffic is not covered by
0.0.0.0/0. Configure an IPv6 tunnel separately before claiming that every IPv4 and IPv6 packet uses the VPN.
Prerequisites:
- A Raff Ubuntu 24.04 VM with a public IPv4 address
- SSH access with sudo privileges
- A client device running Linux, macOS, Windows, Android, or iOS
- UDP port
51820available on the VM - A client network that does not already use
10.90.90.0/24
This tutorial uses:
| Item | Value |
|---|---|
| WireGuard interface | wg0 |
| VPN subnet | 10.90.90.0/24 |
| Server VPN IP | 10.90.90.1/24 |
| First client VPN IP | 10.90.90.2/32 |
| WireGuard port | 51820/udp |
Step 1 — Install WireGuard on Ubuntu 24.04
Update the package index and install WireGuard plus the firewall tools used in the tutorial:
sudo apt update sudo apt install -y wireguard ufw iptables curl
Verify the userspace tools:
wg --version wg-quick --help 2>&1 | head
Load the WireGuard kernel module and confirm it is available:
sudo modprobe wireguard lsmod | grep '^wireguard'
On Ubuntu 24.04, WireGuard support is part of the standard kernel. The wireguard package supplies tools such as wg and wg-quick.
Verification is complete when wg --version succeeds and the wireguard module is available.
Step 2 — Generate the server key pair safely
Create the WireGuard configuration directory with restrictive permissions:
sudo install -d -m 700 /etc/wireguard
Generate the server private key without printing it to the terminal:
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server_private.key'
Derive the public key:
sudo sh -c 'wg pubkey < /etc/wireguard/server_private.key > /etc/wireguard/server_public.key'
Set explicit permissions:
sudo chmod 600 /etc/wireguard/server_private.key sudo chmod 644 /etc/wireguard/server_public.key
Display only the public key:
sudo cat /etc/wireguard/server_public.key
Check the permissions:
sudo ls -l /etc/wireguard/server_private.key /etc/wireguard/server_public.key
Expected permissions include:
-rw------- ... server_private.key -rw-r--r-- ... server_public.key
Do not paste or screenshot the private key. Anyone who obtains it can impersonate that WireGuard peer.
Verification is complete when both key files exist and only root can read the server private key.
Step 3 — Identify the public interface and enable IPv4 forwarding
Find the interface Ubuntu uses for its default IPv4 route:
OUT_IFACE="$(ip route show default | awk '/default/ {print $5; exit}')" printf 'Outbound interface: %s\n' "$OUT_IFACE"
Typical names include eth0, ens3, and similar names. Do not hardcode eth0 without checking the VM.
Create a dedicated sysctl file for WireGuard routing:
sudo tee /etc/sysctl.d/70-wireguard-routing.conf > /dev/null <<'EOF' net.ipv4.ip_forward = 1 EOF
Apply it immediately:
sudo sysctl -p /etc/sysctl.d/70-wireguard-routing.conf
Verify forwarding:
sysctl net.ipv4.ip_forward
Expected output:
net.ipv4.ip_forward = 1
Ubuntu’s current WireGuard default-gateway guidance requires both IPv4 forwarding and masquerading on the gateway server.
Verification is complete when the outbound interface is identified and net.ipv4.ip_forward equals 1.
Step 4 — Create the WireGuard server configuration
Load the server private key into a temporary shell variable and re-detect the outbound interface:
SERVER_PRIVATE_KEY="$(sudo cat /etc/wireguard/server_private.key)" OUT_IFACE="$(ip route show default | awk '/default/ {print $5; exit}')"
Create /etc/wireguard/wg0.conf:
sudo tee /etc/wireguard/wg0.conf > /dev/null <<EOF [Interface] Address = 10.90.90.1/24 ListenPort = 51820 PrivateKey = ${SERVER_PRIVATE_KEY} SaveConfig = false PostUp = iptables -A FORWARD -i %i -o ${OUT_IFACE} -j ACCEPT; iptables -A FORWARD -i ${OUT_IFACE} -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.90.90.0/24 -o ${OUT_IFACE} -j MASQUERADE PostDown = iptables -D FORWARD -i %i -o ${OUT_IFACE} -j ACCEPT; iptables -D FORWARD -i ${OUT_IFACE} -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.90.90.0/24 -o ${OUT_IFACE} -j MASQUERADE EOF unset SERVER_PRIVATE_KEY
Protect the configuration:
sudo chmod 600 /etc/wireguard/wg0.conf
The NAT rule is restricted to the WireGuard subnet instead of masquerading unrelated VM traffic.
Validate the non-secret settings without dumping the private key:
sudo grep -E '^(Address|ListenPort|PostUp|PostDown)' /etc/wireguard/wg0.conf
Expected output includes:
Address = 10.90.90.1/24 ListenPort = 51820
Verification is complete when wg0.conf is mode 600, uses the detected outbound interface, and scopes masquerading to 10.90.90.0/24.
Step 5 — Allow WireGuard through UFW
Always keep the current SSH path allowed before changing firewall rules:
sudo ufw allow OpenSSH
Allow the WireGuard UDP port:
sudo ufw allow 51820/udp
Enable UFW if it is not already active:
sudo ufw --force enable
Review the rules:
sudo ufw status numbered
Expected output includes an SSH allow rule and:
51820/udp ALLOW IN
WireGuard uses UDP. There is no reason to open TCP port 51820 for this configuration.
Verification is complete when SSH remains reachable and UDP 51820 is allowed.
Step 6 — Generate the client key pair and add the peer
Generate the client private key on the client device when possible. This keeps the client private key off the server.
On a Linux client, install WireGuard:
sudo apt update sudo apt install -y wireguard resolvconf
Generate the client key pair:
umask 077 wg genkey > ~/wg-client-private.key wg pubkey < ~/wg-client-private.key > ~/wg-client-public.key
Display only the public key:
cat ~/wg-client-public.key
Copy that public key to the server. On the server, append the peer block to wg0.conf, replacing CLIENT_PUBLIC_KEY:
sudo tee -a /etc/wireguard/wg0.conf > /dev/null <<'EOF' [Peer] PublicKey = CLIENT_PUBLIC_KEY AllowedIPs = 10.90.90.2/32 EOF
Confirm that the peer block exists without printing private material:
sudo grep -A2 '^\[Peer\]' /etc/wireguard/wg0.conf
Expected output includes:
[Peer] PublicKey = CLIENT_PUBLIC_KEY AllowedIPs = 10.90.90.2/32
Replace the placeholder before continuing.
Verification is complete when the client has its own private key and the server contains only that client’s public key plus 10.90.90.2/32.
Step 7 — Start the WireGuard server
Test the configuration by bringing up wg0:
sudo wg-quick up wg0
Check the interface:
ip -4 addr show wg0 sudo wg show wg0
Expected state includes:
10.90.90.1/24 listening port: 51820 allowed ips: 10.90.90.2/32
Verify the NAT rule is present:
sudo iptables -t nat -S POSTROUTING | grep '10.90.90.0/24'
Then enable the interface at boot:
sudo systemctl enable wg-quick@wg0
Check service state:
systemctl is-enabled wg-quick@wg0 systemctl is-active wg-quick@wg0
Expected output:
enabled active
Verification is complete when wg0 owns 10.90.90.1/24, listens on UDP 51820, and the scoped masquerade rule exists.
Step 8 — Configure the client for full-tunnel IPv4 routing
Get the server public key on the server:
sudo cat /etc/wireguard/server_public.key
Get the Raff VM public IPv4 address from the dashboard or with:
curl -4s https://icanhazip.com
On a Linux client, load the client private key into a temporary variable:
CLIENT_PRIVATE_KEY="$(cat ~/wg-client-private.key)"
Create /etc/wireguard/wg0.conf, replacing SERVER_PUBLIC_KEY and your_server_ip:
sudo tee /etc/wireguard/wg0.conf > /dev/null <<EOF [Interface] PrivateKey = ${CLIENT_PRIVATE_KEY} Address = 10.90.90.2/24 DNS = 1.1.1.1 [Peer] PublicKey = SERVER_PUBLIC_KEY Endpoint = your_server_ip:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 EOF unset CLIENT_PRIVATE_KEY sudo chmod 600 /etc/wireguard/wg0.conf
AllowedIPs = 0.0.0.0/0 makes WireGuard the default route for IPv4. WireGuard’s documentation recommends a persistent keepalive interval such as 25 seconds when a peer behind NAT must keep its mapping alive.
Bring up the client tunnel:
sudo wg-quick up wg0
Verify the interface and routes:
ip -4 addr show wg0 sudo wg show wg0 ip route get 1.1.1.1
Expected state: wg0 has 10.90.90.2/24, the peer endpoint is the Raff VM, and the IPv4 default-route handling uses WireGuard.
On Windows, macOS, Android, or iOS, create the same interface/peer values in the official WireGuard application instead of using wg-quick.
Verification is complete when the client tunnel is active and the WireGuard peer is configured with 0.0.0.0/0.
Step 9 — Verify the full-tunnel VPN end to end
From the client, reach the server’s VPN address:
ping -c 4 10.90.90.1
Verify public IPv4 egress through the tunnel:
curl -4s https://icanhazip.com
The result should match the Raff VM’s public IPv4 address.
On the server, inspect the peer:
sudo wg show wg0
A connected peer should show:
latest handshake: ... transfer: ... received, ... sent
Check the client route again:
ip route get 1.1.1.1
If the client has IPv6 connectivity, test it separately:
curl -6 --connect-timeout 5 https://icanhazip.com || echo 'No working IPv6 path'
If that command succeeds, IPv6 is still outside this IPv4-only tunnel. Configure IPv6 addressing, forwarding, firewalling, and routing separately before treating the VPN as an all-protocol full tunnel.
End-to-end verification is complete when:
10.90.90.1responds through the tunnel- The client’s public IPv4 address matches the Raff VM
wg showreports a recent handshake- Transfer counters increase
- The route to an IPv4 internet destination uses the WireGuard full-tunnel policy
