WireGuard is a modern VPN built into the Linux kernel. Compared with OpenVPN or IPsec it has a tiny configuration, connects almost instantly, and is very fast. On a VPS, a WireGuard server gives you an encrypted tunnel for public Wi-Fi, a stable exit IP for allow-listing, or private access to services you don’t want on the internet.
This guide sets up a server on Ubuntu 22.04+/Debian 12+ and adds clients.
How WireGuard works (in one paragraph)
Each device — server and clients — has a key pair. Peers know each other’s public keys and which IPs belong to each peer (AllowedIPs). There’s no username or password, no certificates and no handshake chatter: if a packet isn’t signed by a known key, WireGuard silently ignores it, so the port doesn’t even appear open to scanners.
1. Install
sudo apt update
sudo apt install -y wireguard qrencode
qrencode lets you show client configs as QR codes for the mobile apps.
2. Generate the server keys
cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
3. Find your public interface
ip -br addr
ip route | grep default
Note the interface on the default route — e.g. eth0.
4. Create the server config
/etc/wireguard/wg0.conf:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
# NAT VPN traffic out of the public interface
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
Replace eth0 with your interface. 10.8.0.0/24 is the private VPN subnet; pick another if it clashes with a network you use.
5. Enable IP forwarding
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system
6. Open the port and start
sudo ufw allow 51820/udp
sudo systemctl enable --now wg-quick@wg0
sudo wg show
If UFW is active, also allow forwarding: set DEFAULT_FORWARD_POLICY="ACCEPT" in /etc/default/ufw, or add sudo ufw route allow in on wg0 out on eth0, then sudo ufw reload.
7. Add a client
Generate keys for the client (on the server for convenience, or on the client device itself, which is better practice):
cd /etc/wireguard
wg genkey | tee phone.key | wg pubkey > phone.pub
Add the peer to the server:
sudo wg set wg0 peer $(cat phone.pub) allowed-ips 10.8.0.2/32
sudo wg-quick save wg0 # writes the running config back to wg0.conf
Or append to wg0.conf by hand and restart:
[Peer]
PublicKey = <contents of phone.pub>
AllowedIPs = 10.8.0.2/32
Each client gets its own /32 address.
Create the client config, phone.conf:
[Interface]
PrivateKey = <contents of phone.key>
Address = 10.8.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <contents of server.pub>
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0, ::/0sends all traffic through the VPN (full tunnel). To reach only the VPN subnet (split tunnel), use10.8.0.0/24.PersistentKeepalive = 25keeps the tunnel alive through NAT routers — useful for phones and laptops.
8. Import on the device
- Phone: show a QR code and scan it in the WireGuard app:
qrencode -t ansiutf8 < phone.conf
- Windows / macOS: install the WireGuard app and import
phone.conf. - Linux: copy it to
/etc/wireguard/wg0.confand runsudo wg-quick up wg0.
Delete client private keys from the server once they’re imported.
9. Test
On the client, browse to an IP-check site — it should show the server’s IP. On the server:
sudo wg show
A recent latest handshake and growing transfer counters mean the peer is connected.
Troubleshooting
- No handshake at all — UDP 51820 is blocked (UFW, provider firewall, or the client’s network), or the endpoint IP/port is wrong. Also check that the public keys are swapped correctly: the server needs the client’s public key and vice versa.
- Handshake works but no internet — IP forwarding or NAT is missing; check
sysctl net.ipv4.ip_forwardandiptables -t nat -L -n -v, and the interface name inPostUp. - Websites don’t load, but pings to IPs work — DNS; set
DNS =in the client config. - Some sites hang — MTU issues; set
MTU = 1380in the client’s[Interface].
Managing many clients
For more than a handful of users, tools such as wg-easy (a web UI in Docker) or Headscale/Tailscale (mesh networking with automatic key exchange) save time. See Tailscale on a VPS and OpenVPN vs WireGuard.
Choosing the server location
Your VPN exit is where the VPS is. For low latency, pick a location near you or near the services you use — our Hong Kong and Tokyo locations suit users across Asia, and USA locations cover the Americas. More background in setting up a VPN on a VPS.