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, ::/0 sends all traffic through the VPN (full tunnel). To reach only the VPN subnet (split tunnel), use 10.8.0.0/24.
  • PersistentKeepalive = 25 keeps 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.conf and run sudo 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_forward and iptables -t nat -L -n -v, and the interface name in PostUp.
  • Websites don’t load, but pings to IPs work — DNS; set DNS = in the client config.
  • Some sites hang — MTU issues; set MTU = 1380 in 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.

  • WireGuard
  • VPN
  • Networking