Set Up WireGuard VPN Server on VPS Ubuntu: Step-by-Step Guide

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:

Prerequisites

Before starting, ensure you have the following in place:

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:

  1. Import a .conf file — Transfer the client1.conf file to your phone and import it directly into the WireGuard app.
  2. Scan a QR code — Install qrencode on the server (sudo apt install qrencode), then generate a QR code with qrencode -t ansiutf8 < client1.conf and 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:

  1. Generate a new key pair for the client.
  2. Distribute the new client config before revoking the old key — this avoids a gap in connectivity.
  3. Replace the old [Peer] block with the new public key in wg0.conf.
  4. 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:

Troubleshooting Common Issues

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

View all affordable VPS Thailand plans →