
Running your own VPN server on a VPS gives you full control over your privacy, lets you securely access private networks from anywhere in the world, and protects your traffic on untrusted public networks. WireGuard is the modern VPN protocol of choice — it is significantly faster and simpler to configure than OpenVPN while using state-of-the-art cryptography. This guide walks you through every step to get a WireGuard VPN server running on Ubuntu VPS.
What is WireGuard and Why is it Better than OpenVPN?
WireGuard is a modern VPN protocol designed for simplicity, speed, and security. Its codebase is approximately 4,000 lines — a fraction of OpenVPN's 600,000+ lines — making it far easier to audit and maintain.
Key advantages of WireGuard over OpenVPN:
- Faster throughput — WireGuard runs inside the Linux kernel, delivering lower latency and higher throughput than OpenVPN's userspace implementation.
- Simpler configuration — Uses public/private key pairs similar to SSH, with no need for a complex Certificate Authority.
- Rapid reconnection — Handshakes complete in milliseconds, making it ideal for mobile devices that frequently switch between networks.
- Modern cryptography — Uses Curve25519 for key exchange, ChaCha20 for encryption, and Poly1305 for authentication — all well-vetted, high-performance algorithms.
- Built into the Linux kernel — Available natively from kernel 5.6 onward (Ubuntu 20.04+), requiring no additional kernel modules.
Prerequisites
Before starting, ensure you have the following in place:
- A VPS running Ubuntu 20.04 or 22.04 with root or sudo access.
- A static public IP address for the VPS (verify with
curl ifconfig.me). - UDP port 51820 not blocked by your VPS provider's upstream firewall.
- Ability to modify kernel parameters (
net.ipv4.ip_forward).
Step 1: Install WireGuard
SSH into your VPS and run the following commands:
sudo apt update sudo apt install wireguard -y
Verify the installation:
wg --version
Step 2: Generate a Server Key Pair
WireGuard uses Elliptic Curve Cryptography (Curve25519) for key exchange. Generate a key pair for the server:
cd /etc/wireguard wg genkey | sudo tee server_private.key | wg pubkey | sudo tee server_public.key sudo chmod 600 /etc/wireguard/server_private.key
Display and note the private key — you will need it in the next step:
sudo cat /etc/wireguard/server_private.key
Also note the server public key, as clients will need it:
sudo cat /etc/wireguard/server_public.key
Step 3: Configure the Server Interface (wg0.conf)
Create the configuration file for the wg0 interface:
sudo nano /etc/wireguard/wg0.conf
Add the following content, replacing YOUR_SERVER_PRIVATE_KEY with your actual server private key:
[Interface] Address = 10.0.0.1/24 ListenPort = 51820 PrivateKey = YOUR_SERVER_PRIVATE_KEY # IP Forwarding and NAT rules PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Note: If your VPS network interface is not eth0, check the correct name with ip route show default and substitute it in the PostUp/PostDown lines.
Step 4: Enable IP Forwarding and Configure UFW
Enable IP forwarding so the VPS can route client traffic to the internet:
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p
Open the WireGuard UDP port in UFW and ensure SSH remains accessible:
sudo ufw allow 51820/udp sudo ufw allow OpenSSH sudo ufw enable sudo ufw status
Step 5: Generate a Client Key Pair
Generate a separate key pair for each client device. Repeat this process for every device you want to add:
wg genkey | sudo tee /etc/wireguard/client1_private.key | wg pubkey | sudo tee /etc/wireguard/client1_public.key
Note the client private key:
sudo cat /etc/wireguard/client1_private.key
Note the client public key (needed in the server config):
sudo cat /etc/wireguard/client1_public.key
Step 6: Add a Peer (Client) to the Server Config
Open /etc/wireguard/wg0.conf and append a Peer block:
[Peer] # Client 1 - My Laptop PublicKey = CLIENT1_PUBLIC_KEY AllowedIPs = 10.0.0.2/32
Replace CLIENT1_PUBLIC_KEY with the client public key generated in the previous step. The AllowedIPs field assigns a fixed VPN IP to this client.
Step 7: Create the Client Configuration
Create a configuration file for the client device (save as client1.conf):
[Interface] PrivateKey = CLIENT1_PRIVATE_KEY Address = 10.0.0.2/32 DNS = 1.1.1.1 [Peer] PublicKey = SERVER_PUBLIC_KEY Endpoint = YOUR_VPS_PUBLIC_IP:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25
Replace the placeholder values with your actual keys and VPS IP address. Setting AllowedIPs = 0.0.0.0/0 routes all traffic through the VPN (full tunnel). For split tunneling, specify only the IP ranges you want to route over the VPN.
Step 8: Start WireGuard and Test the Connection
Bring up the WireGuard interface on the server:
sudo wg-quick up wg0
Check the interface status and confirm the peer is listed:
sudo wg show
Connect your client device, then test connectivity by pinging the server's VPN address:
ping 10.0.0.1
To verify your public IP has changed to the VPS IP:
curl ifconfig.me
Enable WireGuard to Start Automatically After Reboot
Run these commands to ensure WireGuard starts automatically whenever the VPS is rebooted:
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
Check the service status at any time with: sudo systemctl status wg-quick@wg0
Managing Multiple Peers and Key Rotation
In real-world deployments you will typically need to connect multiple devices — a laptop, a smartphone, and a tablet, for example. WireGuard handles this cleanly: each peer gets its own VPN IP address and an independent key pair, so compromising one device does not affect others.
Generate separate key pairs for every additional device:
wg genkey | sudo tee /etc/wireguard/client2_private.key | wg pubkey | sudo tee /etc/wireguard/client2_public.key wg genkey | sudo tee /etc/wireguard/client3_private.key | wg pubkey | sudo tee /etc/wireguard/client3_public.key
Append a [Peer] block for each device in /etc/wireguard/wg0.conf:
[Peer] # Client 2 - Mobile Phone PublicKey = CLIENT2_PUBLIC_KEY AllowedIPs = 10.0.0.3/32 [Peer] # Client 3 - Tablet PublicKey = CLIENT3_PUBLIC_KEY AllowedIPs = 10.0.0.4/32
You can add a peer at runtime without restarting the interface:
sudo wg set wg0 peer CLIENT2_PUBLIC_KEY allowed-ips 10.0.0.3/32
For permanent changes, edit wg0.conf and reload: sudo wg-quick down wg0 && sudo wg-quick up wg0. To revoke access for a device, simply remove its [Peer] block and reload.
WireGuard vs OpenVPN vs IPsec: Feature Comparison
| Feature | WireGuard | OpenVPN | IPsec |
|---|---|---|---|
| Code size | ~4,000 lines | >600,000 lines | Very large |
| Throughput | Very high (kernel) | Moderate (userspace) | High (kernel) |
| Setup complexity | Low (key pairs only) | High (CA, certs) | Very high |
| Handshake time | <100 ms | 1–3 seconds | 0.5–1 second |
| Linux kernel built-in | Yes (kernel 5.6+) | No (install required) | Partial |
Split Tunneling and DNS Leak Prevention
Setting AllowedIPs = 0.0.0.0/0 routes all traffic through the VPN (full tunnel). In many cases you will want split tunneling, where only specific destinations are routed over the VPN while other traffic goes directly to the internet.
Example split tunnel configuration — route only the VPN subnet and a private network:
[Peer] PublicKey = SERVER_PUBLIC_KEY Endpoint = YOUR_VPS_IP:51820 AllowedIPs = 10.0.0.0/24, 192.168.1.0/24 PersistentKeepalive = 25
For full tunnel setups, always specify a trusted DNS server to prevent DNS leaks. In the client [Interface] section:
[Interface] DNS = 1.1.1.1, 8.8.8.8
After connecting, verify there are no DNS leaks at dnsleaktest.com — the DNS servers shown should be Cloudflare (1.1.1.1) or Google (8.8.8.8), not your ISP's resolver.
Monitoring and Debugging WireGuard
The wg show command provides a real-time view of all peers and their connection status:
sudo wg show
A healthy, connected peer looks like this:
interface: wg0 public key: [server_public_key] private key: (hidden) listening port: 51820 peer: [client1_public_key] endpoint: [client_ip]:PORT allowed ips: 10.0.0.2/32 latest handshake: 23 seconds ago transfer: 1.23 MiB received, 456 KiB sent
If latest handshake shows a long time ago or is absent, the peer is not actively connected. Use these commands to diagnose:
# Check firewall status sudo ufw status verbose # Confirm current VPS public IP curl ifconfig.me # View WireGuard logs sudo journalctl -u wg-quick@wg0 -f
Adding Clients on iOS and Android
WireGuard has official apps for both iOS and Android. You can import the client configuration in two ways:
- Import a .conf file — Transfer the
client1.conffile to your phone and import it directly into the WireGuard app. - Scan a QR code — Install
qrencodeon the server (sudo apt install qrencode), then generate a QR code withqrencode -t ansiutf8 < client1.confand scan it with the WireGuard app.
After importing, toggle the tunnel on and verify your internet connection works normally and your IP address reflects the VPS location.
Key Rotation and Revoking Client Access
Managing keys properly is critical in any production WireGuard deployment. When you need to revoke a client's access — for example, because a device was lost or an employee left — simply remove that client's [Peer] block from wg0.conf and reload the interface. The client is instantly locked out without affecting any other peers.
For periodic key rotation, follow this sequence to avoid disrupting connectivity:
- Generate a new key pair for the client.
- Distribute the new client config before revoking the old key — this avoids a gap in connectivity.
- Replace the old
[Peer]block with the new public key inwg0.conf. - Apply the change without a full restart:
sudo wg syncconf wg0 <(wg-quick strip wg0)
WireGuard also supports Pre-shared Keys (PSK) — a per-peer symmetric key that adds a second layer of protection on top of Curve25519. Even if elliptic curve cryptography were ever compromised, the PSK provides additional defense. Generate one with:
wg genpsk | sudo tee /etc/wireguard/client1.psk
sudo chmod 600 /etc/wireguard/client1.psk
Add PresharedKey = [psk_value] to the [Peer] block on both the server and the client config file.
WireGuard Behind NAT and Cloud Firewalls
If your VPS provider uses an upstream network firewall or Security Group (common with AWS, DigitalOcean, GCP, and similar platforms), you must open UDP port 51820 in the provider's console in addition to allowing it through UFW. The provider's firewall operates before UFW and silently drops packets that never reach the OS-level firewall.
To verify port 51820 is reachable from the public internet:
# From a different machine — check if UDP 51820 is open
nmap -sU -p 51820 YOUR_VPS_IP
# Quick UDP reachability check (no response expected — WireGuard is silent to non-peers)
nc -vuz YOUR_VPS_IP 51820
WireGuard is deliberately "silent" — it does not respond to packets from unknown public keys, so a port scanner may show it as "filtered" even when it is working correctly. The definitive test is a successful handshake from a configured client.
| Scenario | Action Required | How to Verify |
|---|---|---|
| VPS with direct public IP | UFW allow 51820/udp only | sudo ufw status |
| Cloud Security Group (AWS/DO/GCP) | Add inbound UDP 51820 in cloud console | nmap -sU -p 51820 IP |
| VPS behind NAT | Port-forward UDP 51820 on router/gateway | curl ifconfig.me vs assigned IP |
Security Best Practices for WireGuard Server
Getting WireGuard running is just the starting point. For a production VPN server, apply these hardening practices:
- Restrict key file permissions — Private keys must be readable only by root. Confirm with
ls -la /etc/wireguard/*.key— permissions should show-rw-------(600). - Back up wg0.conf securely — Store an encrypted copy in a password manager or secure vault. If the private key is lost, every client must be reconfigured with a new key pair.
- Audit inactive peers — Any peer that has not completed a handshake in 7 or more days is likely stale. Remove it to keep your
wg0.confclean and reduce the attack surface. - Protect SSH alongside WireGuard — Install Fail2ban or similar to rate-limit SSH login attempts. WireGuard itself cannot be brute-forced (cryptographic handshakes, no username/password), but SSH on port 22 remains a common target.
- Keep the kernel updated — WireGuard is part of the Linux kernel from 5.6 onward. Regular kernel updates deliver security patches that benefit WireGuard directly.
- One device, one key pair — Never share private keys across devices. If a new device needs VPN access, generate a fresh key pair and add it as a separate peer.
- Minimize open ports — On a dedicated VPN VPS, only UDP 51820 (WireGuard) and TCP 22 (SSH) need to be open. Close everything else via UFW.
Troubleshooting Common Issues
- Cannot ping server VPN IP — Check that the UFW rule for port 51820/udp is active (
sudo ufw status) and that the wg0 interface is up (sudo wg show). - No internet through VPN — Confirm IP forwarding is enabled (
sysctl net.ipv4.ip_forwardshould return 1) and check the PostUp iptables rules were applied. - Wrong network interface in PostUp — If eth0 is not your main interface, identify the correct one with
ip route show default | awk '{print $5}'. - Client shows "handshake" but no traffic — Ensure
AllowedIPs = 0.0.0.0/0is set on the client and the DNS is reachable over the VPN.
VPS with WireGuard Kernel Support
AsiaGB Ubuntu VPS plans support WireGuard natively with no additional configuration. Get a public IP, full root access, and unmetered bandwidth — starting from 500 THB/month with 99% uptime guarantee.
View VPS Plans