How to Setup WireGuard VPN on Ubuntu: Step-by-Step Guide
Introduction to WireGuard VPN on Ubuntu
What is WireGuard?
WireGuard is a modern VPN protocol that creates an encrypted tunnel between two or more devices. It lives inside the Linux kernel, which means it can move packets faster than traditional user‑space solutions.
Why Choose WireGuard Over OpenVPN?
OpenVPN is reliable, but its code base is massive and it runs in user space. WireGuard’s code is tiny, its cryptography is up‑to‑date, and it typically delivers 2‑4× higher throughput on the same hardware. The simplicity of its configuration files also reduces the chance of human error.
Prerequisites and System Requirements
Ubuntu Version Compatibility
- Ubuntu 20.04 LTS or newer – the package is in the official repositories.
- Older releases (e.g., 18.04) work if you enable the
wireguardbackports repository.
Root or Sudo Access
You must run every command that touches network interfaces or firewall rules with sudo. If you use a non‑root user, add it to the sudo group first.
Network and Firewall Requirements
- UDP port 51820 (or a custom port you choose) must be reachable from the Internet.
- IP forwarding needs to be turned on so traffic can pass through the server.
- If you use
ufw, allow the chosen port and enable NAT.
Step-by-Step Installation of WireGuard
Updating System Packages
sudo apt update && sudo apt upgrade -y
Installing WireGuard Tools
sudo apt install -y wireguard wireguard-tools qrencode
The qrencode package makes it easy to generate QR codes for mobile clients.
Generating Public and Private Keys
Run the commands on the server first, then repeat for each client.
# Server keys
sudo mkdir -p /etc/wireguard/keys
sudo wg genkey | tee /etc/wireguard/keys/server_private.key | wg pubkey > /etc/wireguard/keys/server_public.key
sudo chmod 600 /etc/wireguard/keys/server_private.key
# Client keys (replace “client1” with a descriptive name)
sudo wg genkey | tee /etc/wireguard/keys/client1_private.key | wg pubkey > /etc/wireguard/keys/client1_public.key
sudo chmod 600 /etc/wireguard/keys/client1_private.key
Store the private keys with chmod 600. Never share them.
Configuring the WireGuard Server
Creating the wg0.conf File
sudo nano /etc/wireguard/wg0.conf
Paste the following template and replace the placeholders with the keys you generated:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
# Optional: improve performance on PPPoE links
MTU = 1420
# NAT for Internet‑bound traffic
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# DNS that clients will use when the tunnel is up
DNS = 1.1.1.1
# Example peer (client1)
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32
Save and exit. The PostUp/PostDown lines add and remove NAT automatically when the interface starts or stops.
Setting Up IP Forwarding
Enable forwarding permanently:
sudo sysctl -w net.ipv4.ip_forward=1
sudo sed -i '/^#*net.ipv4.ip_forward/s/^#*//' /etc/sysctl.conf
sudo sysctl -p
Configuring UFW Firewall Rules
sudo ufw allow 51820/udp
sudo ufw enable # if not already active
If you run a more complex firewall (nftables, firewalld) adapt the rule accordingly.
Starting and Enabling the Service
sudo systemctl start wg-quick@wg0
sudo systemctl enable wg-quick@wg0
Check the status:
sudo systemctl status wg-quick@wg0
Setting Up WireGuard Clients
Creating Client Configuration Files
On the server, generate a client config that points back to the server’s public IP (or DDNS hostname).
cat > /etc/wireguard/client1.conf <<EOF
[Interface]
PrivateKey = <CLIENT1_PRIVATE_KEY>
Address = 10.0.0.2/32
DNS = 1.1.1.1
MTU = 1420
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = your.server.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
Copy client1.conf to the client device using scp, a USB stick, or any secure channel.
Connecting from Windows, macOS, or Android
- Windows/macOS: Install the official WireGuard app, import the
.conffile, and toggle the tunnel. - Android/iOS: Install the WireGuard mobile app, tap the “+” button, then “Create from file or archive”.
For mobile devices you can generate a QR code on the server:
qrencode -t ansiutf8 -l L < /etc/wireguard/client1.conf
Testing the VPN Connection
After the client reports “Connected”, verify that traffic goes through the tunnel:
# On the client
curl ifconfig.me # should show the server’s public IP
wg show # handshake time should be recent
ip route # should contain 10.0.0.0/24 via wg0
Best Practices for WireGuard Security
Managing Key Rotation
Store each peer’s keys in /etc/wireguard/keys. When a key is compromised, replace only that peer’s PublicKey entry and reload the config:
sudo wg set wg0 peer <OLD_PUBLIC_KEY> remove
sudo wg set wg0 peer <NEW_PUBLIC_KEY> allowed-ips 10.0.0.2/32
sudo systemctl reload wg-quick@wg0
Implementing Strong Firewall Policies
- Limit inbound traffic to the chosen UDP port.
- Block all other inbound traffic on
wg0withiptables -A INPUT -i wg0 -j DROPif you only need outbound routing. - Log rejected packets for later audit.
Using a Non‑Standard Port
Changing the listening port can reduce automated scans. Edit ListenPort in wg0.conf, update the firewall rule, and restart the service.
Common Mistakes and Troubleshooting
Fixing “Handshake Did Not Complete” Errors
Check the following:
- Is UDP port 51820 (or your custom port) open on the server’s firewall?
- Is the client behind a NAT that blocks outbound UDP? Set
PersistentKeepalive = 25in the client config. - Do the public keys match the ones stored in
wg0.conf?
Resolving DNS Leakage Issues
If curl ifconfig.me still shows the ISP’s IP, add a DNS line to the client’s [Interface] section or use a DNS‑over‑TLS resolver (e.g., 1.1.1.1).
Checking WireGuard Service Status
sudo wg show
sudo systemctl status wg-quick@wg0
sudo iptables -t nat -L POSTROUTING -nv
Look for a recent handshake timestamp and a NAT rule that masquerades outbound traffic.