How to Install and Secure WireGuard VPN on Ubuntu 24.04 (IPv6, UFW, and Mobile QR Codes)

Overview

WireGuard is a modern VPN that is fast, secure, and simple to manage. In this step-by-step guide, you will install a WireGuard server on Ubuntu 24.04 LTS, enable IPv4/IPv6 routing, lock it down with UFW firewall, and create a mobile-friendly client using a QR code. This setup is ideal for remote access, secure public Wi‑Fi, and self-hosted lab environments.

Prerequisites

You need an Ubuntu 24.04 server (root or sudo), a public IP or DNS record pointing to your server, and one open UDP port (default: 51820). Update your system and note the name of your Internet-facing interface (e.g., eth0 or ens3).

1) Install WireGuard and tools

Install core packages and utilities used for key generation and QR export.

sudo apt update && sudo apt -y install wireguard qrencode resolvconf

2) Enable IP forwarding (IPv4 and IPv6)

Allow the server to route traffic from VPN clients to the Internet. Create a sysctl drop-in so the setting persists across reboots.

sudo tee /etc/sysctl.d/99-wireguard-routing.conf >/dev/null <<'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
sudo sysctl --system

3) Generate server keys

WireGuard uses public-key cryptography. Generate a private key, derive the public key, and keep the private key secret.

umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey | tee /etc/wireguard/server.pub
SERVER_PRIV=$(cat /etc/wireguard/server.key)

4) Create the server interface configuration

In this example, clients will use the subnets 10.8.0.0/24 (IPv4) and fd86:ea04:1111::/64 (IPv6). Replace eth0 with your real outbound interface. PostUp/PostDown rules enable NAT and forwarding for both stacks.

sudo tee /etc/wireguard/wg0.conf >/dev/null <<'EOF'
[Interface]
Address = 10.8.0.1/24, fd86:ea04:1111::1/64
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
# NAT and forwarding for IPv4/IPv6
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; \
         iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; \
         ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; \
         ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -A FORWARD -o %i -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; \
           iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; \
           ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; \
           ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -D FORWARD -o %i -j ACCEPT
SaveConfig = false
EOF
sudo sed -i "s|SERVER_PRIVATE_KEY|$SERVER_PRIV|" /etc/wireguard/wg0.conf

If your server uses another outbound interface name, replace eth0 in PostUp/PostDown accordingly. If you prefer nftables, you can translate these rules to nft syntax.

5) Open the firewall

Allow UDP 51820 so peers can reach your VPN. If you use UFW, run:

sudo ufw allow 51820/udp
sudo ufw status verbose

6) Start WireGuard and enable on boot

The wg-quick helper reads the configuration and brings up the interface. Enable the service to auto-start on reboot.

sudo systemctl enable --now wg-quick@wg0
sudo wg show

7) Create your first client (peer)

Generate keys for a client, define which subnets to route through the tunnel (0.0.0.0/0 and ::/0 for full-tunnel), and set DNS to prevent leaks. Replace vpn.example.com with your server’s public IP or domain. PersistentKeepalive helps mobile devices behind NATs maintain connectivity.

umask 077
wg genkey | tee ~/alice.key | wg pubkey | tee ~/alice.pub
ALICE_PRIV=$(cat ~/alice.key)
ALICE_PUB=$(cat ~/alice.pub)
SERVER_PUB=$(cat /etc/wireguard/server.pub)
SERVER_ENDPOINT="vpn.example.com:51820"

Add the client as a peer on the server and assign an IP:

sudo tee -a /etc/wireguard/wg0.conf >/dev/null <<EOF
[Peer]
# Alice
PublicKey = $ALICE_PUB
AllowedIPs = 10.8.0.2/32, fd86:ea04:1111::2/128
EOF
sudo systemctl restart wg-quick@wg0
sudo wg show

Build the client configuration file:

cat > ~/alice.conf <<EOF
[Interface]
PrivateKey = $ALICE_PRIV
Address = 10.8.0.2/32, fd86:ea04:1111::2/128
DNS = 1.1.1.1, 2606:4700:4700::1111

[Peer]
PublicKey = $SERVER_PUB
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = $SERVER_ENDPOINT
PersistentKeepalive = 25
EOF

Tip: For privacy, you can run a resolver like Unbound on the server and set DNS = 10.8.0.1, fd86:ea04:1111::1.

8) Import on mobile via QR code

The WireGuard apps for Android and iOS can import a profile from a QR code. Print it in the terminal and scan it with the app.

qrencode -t ansiutf8 < ~/alice.conf

Alternatively, transfer the file securely and import it in the desktop or mobile WireGuard client.

9) Test your connection

Connect the client and verify your public IP changes. You can use curl ifconfig.io or any IP check site. Also test DNS and IPv6.

# On the client after connecting
curl -4 ifconfig.io
curl -6 ifconfig.io
nslookup example.org
ping -c 3 10.8.0.1

Troubleshooting

If the interface fails to start, check for typos in wg0.conf and ensure the outbound interface name is correct. Review logs with: sudo journalctl -u wg-quick@wg0 -e. If clients connect but have no Internet, verify IP forwarding (sysctl), NAT rules (PostUp), and that UDP 51820 is open. For DNS leaks or resolution failures, confirm the DNS entries in the client and that your resolver is reachable through the tunnel.

Security Tips

Use a non-default port if your ISP is restrictive, limit SSH access with UFW and key-based auth, keep the kernel and packages updated, and remove peers you no longer need. Consider enabling automatic security updates: sudo apt install unattended-upgrades.

You now have a fast, dual-stack WireGuard VPN on Ubuntu 24.04 with clean routing, firewall rules, and mobile-friendly onboarding via QR codes.

3.

Comments