WireGuard on Ubuntu 24.04: A Zero‑Trust VPN Setup with Windows and Mobile Clients

Overview

WireGuard is a modern VPN protocol that is fast, secure, and simple to deploy. In this tutorial, you will build a production-ready WireGuard server on Ubuntu 24.04 and connect Windows and mobile clients. You will configure routing, firewall rules, auto-start, and testing. The guide uses clear steps and SEO-friendly terms to help you go from zero to a working zero-trust VPN in minutes.

Prerequisites

You need an Ubuntu 24.04 server (cloud VPS or on-prem) with a public IP, sudo access, and UDP port 51820 open on any external firewall. If the server is behind a home router, forward UDP 51820 to the server’s LAN address. For clients, you need a Windows 10/11 PC and an Android or iOS device.

Step 1: Install WireGuard on Ubuntu 24.04

Update packages and install WireGuard tools:
sudo apt update && sudo apt install -y wireguard qrencode

Create a configuration directory and restrict permissions:
sudo mkdir -p /etc/wireguard && sudo chmod 700 /etc/wireguard

Step 2: Generate keys and base server config

Generate the server keypair:
cd /etc/wireguard
sudo wg genkey | sudo tee server_private.key | sudo wg pubkey | sudo tee server_public.key
sudo chmod 600 server_private.key

Set your VPN subnet and interface variables (eth0 is common on cloud VMs; adjust if yours differs):
export WG_IFACE=wg0
export WG_SUBNET=10.7.0.0/24
export SERVER_ADDR=10.7.0.1/24
export WAN_IFACE=eth0

Create the server configuration file:
sudo bash -c 'cat >/etc/wireguard/wg0.conf' <<EOF
[Interface]
Address = 10.7.0.1/24
ListenPort = 51820
PrivateKey = $(cat /etc/wireguard/server_private.key)
# Accept forwarding and NAT to the Internet
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ${WAN_IFACE} -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ${WAN_IFACE} -j MASQUERADE
EOF'

Step 3: Enable IP forwarding and open the port

Enable IPv4 forwarding persistently:
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system

If you use UFW, allow the WireGuard port:
sudo ufw allow 51820/udp

Start and enable the VPN interface:
sudo systemctl enable --now wg-quick@wg0

Check status and listen port:
sudo wg show

Step 4: Add a Windows client

On the server, generate a keypair for your Windows PC (you can also generate on the PC inside the app):
sudo wg genkey | sudo tee win_private.key | sudo wg pubkey | sudo tee win_public.key

Add the Windows peer to the server:
sudo bash -c 'cat >>/etc/wireguard/wg0.conf' <<EOF
[Peer]
PublicKey = $(cat /etc/wireguard/win_public.key)
AllowedIPs = 10.7.0.2/32
EOF'

Then restart the interface:
sudo systemctl restart wg-quick@wg0

On Windows, install the WireGuard app from the official site or Microsoft Store. Create a new tunnel with this configuration (replace placeholders):
[Interface]
PrivateKey = <win_private_key>
Address = 10.7.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public_key>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <server_public_ip>:51820
PersistentKeepalive = 25

Copy values:
<server_public_key> is the content of /etc/wireguard/server_public.key.
<win_private_key> is the content of win_private.key if you generated it on the server, otherwise use the private key generated by the Windows app.
AllowedIPs set to 0.0.0.0/0, ::/0 routes all traffic through the VPN (full tunnel). For split tunnel, use 10.7.0.0/24 only.

Step 5: Add a mobile client (Android/iOS)

On the phone, install the WireGuard app. Creating keys on the device is the most secure method: add a new tunnel, let the app generate keys, and copy the public key.

Add the mobile peer on the server (replace with the phone’s public key and desired IP):
sudo bash -c 'cat >>/etc/wireguard/wg0.conf' <<EOF
[Peer]
PublicKey = <mobile_public_key>
AllowedIPs = 10.7.0.3/32
EOF'
sudo systemctl restart wg-quick@wg0

On the mobile app, create or import a config like this (adjust placeholders):
[Interface]
PrivateKey = <mobile_private_key>
Address = 10.7.0.3/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public_key>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <server_public_ip>:51820
PersistentKeepalive = 25

Optional: if you prefer generating the mobile config on the server and scanning a QR code, create a file (for example /etc/wireguard/mobile1.conf) with the contents above and show a QR in the terminal:
sudo qrencode -t ansiutf8 < /etc/wireguard/mobile1.conf

Step 6: Auto-start, verify, and test

Ensure the interface starts on boot:
sudo systemctl enable wg-quick@wg0

Verify that peers handshaked and received IPs:
sudo wg show

Test connectivity from a client: open a browser and check your public IP (it should show the server’s IP if using a full tunnel). Also, ping the server’s VPN IP:
ping 10.7.0.1

Troubleshooting quick wins

No handshake? Confirm UDP 51820 is open and reachable. Use:
sudo ss -ulpn | grep 51820 on the server to see if it is listening, and sudo tcpdump -ni any udp port 51820 to check if packets arrive.

Wrong interface name? Replace eth0 with your actual outbound interface (check with ip route get 1.1.1.1). Update PostUp/PostDown accordingly and restart the service.

Double NAT issues? Set PersistentKeepalive = 25 on clients and ensure router port forwarding is correct.

Can’t access the Internet from the VPN? Confirm IPv4 forwarding is enabled and that NAT rules exist (see iptables -t nat -S). Also verify AllowedIPs values on both sides.

Security and best practices

Rotate keys periodically and remove stale peers from wg0.conf. Keep Ubuntu and WireGuard updated. Use strong SSH hygiene on the server and restrict management access by IP if possible. For compliance-driven environments, log changes to /etc/wireguard with version control (without committing private keys).

You now have a fast, modern WireGuard VPN on Ubuntu 24.04 with Windows and mobile clients. This layout is minimal yet production-ready and can scale by adding more peers with unique /32 addresses inside the same VPN subnet.

3.

Comments