All systems operational Your IP: 216.73.217.36 info@cloudhosting.lv +371 66 66 29 69 Client area

← All questions

How to set up a WireGuard VPN server on a VPS

This guide walks through setting up a personal WireGuard VPN server on a VPS running Ubuntu 22.04 or 24.04. It is written for developers and sysadmins who want a fast private tunnel for remote access, safe use of public Wi-Fi, or a fixed IP for reaching internal services. By the end you will have a running server, one working client and a QR code you can scan with a phone.

Why WireGuard

WireGuard is the sensible default for a self-hosted VPN today. The reasons are practical:

  • Small codebase. The core is about 4000 lines. OpenVPN plus its TLS stack is orders of magnitude larger, and attack surface grows with code size.
  • Modern crypto, nothing to choose. ChaCha20-Poly1305 for encryption and Curve25519 for key exchange are fixed. There are no cipher suites to misconfigure.
  • Kernel implementation. WireGuard has been in the Linux kernel since 5.6, so even a small VPS pushes traffic at close to line rate with low CPU load.
  • Minimal configuration. A working config is about ten lines, and roaming between Wi-Fi and mobile data is seamless because sessions are bound to keys, not to source addresses.

The trade-off: WireGuard has no user management and no dynamic address pool. Every client is a key pair plus a static tunnel IP that you assign yourself. For one admin and a handful of devices this is a feature, not a limitation.

Install WireGuard and generate keys

All commands below run as root. Install the tools:

apt update
apt install -y wireguard qrencode

Generate a key pair for the server and one for the first client. The umask makes sure the private keys are not world-readable:

cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee client1.key | wg pubkey > client1.pub

A private key never leaves the machine it belongs to. In a strict deployment you would generate the client key on the client device; doing it on the server is acceptable for a first setup, just delete client1.key after importing the config on the phone.

Server configuration

Create /etc/wireguard/wg0.conf. Replace the two placeholders with the actual contents of server.key and client1.pub:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# client1, phone
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32

The PostUp rule turns the VPS into a NAT gateway: packets arriving from the tunnel leave through the public interface with the server's IP. On many images the public interface is called ens3 or enp1s0 rather than eth0. Check it and adjust both lines:

ip route | grep default

NAT does nothing without IP forwarding, which Ubuntu disables by default. Enable it permanently:

echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-wireguard.conf
sysctl --system

Finally, protect the config, since it contains the private key:

chmod 600 /etc/wireguard/wg0.conf

Client configuration and phone QR code

Create client1.conf in the same directory. This file goes to the client device, so it holds the client private key and the server public key:

[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.8.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_VPS_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0 routes all client traffic through the VPN. If you only want to reach the server's internal network, list specific subnets instead, for example 10.8.0.0/24. PersistentKeepalive keeps the NAT mapping alive on mobile networks.

For a phone, install the official WireGuard app from the App Store or Google Play and render the config as a QR code straight in the terminal:

qrencode -t ansiutf8 < client1.conf

In the app choose Add tunnel, then Scan from QR code. No file transfer needed.

Firewall and start

If you use ufw, open the WireGuard port and allow forwarded traffic from the tunnel out to the internet:

ufw allow 51820/udp
ufw route allow in on wg0 out on eth0
ufw reload

Start the tunnel and enable it on boot:

systemctl enable --now wg-quick@wg0
wg show

wg show lists the peer; latest handshake appears once the phone connects. From the client, verify the path end to end:

  • ping 10.8.0.1 confirms the tunnel itself
  • any what-is-my-ip site should now show the VPS address, which confirms NAT

To add more clients, repeat the key generation, pick the next free address (10.8.0.3/32 and so on), append a new [Peer] block to wg0.conf and run systemctl restart wg-quick@wg0, or add the peer live with wg set wg0 peer PUBKEY allowed-ips 10.8.0.3/32.

Sizing and when to hand it off

WireGuard is light. Each peer costs a few kilobytes of state and the kernel handles encryption cheaply, so a VPS with 1 vCPU and 2 GB of RAM comfortably serves dozens of simultaneous clients. The realistic bottleneck is the network port, not the processor, and typical remote-work traffic does not come close to saturating it.

Any of our VPS plans works for this setup; each comes with a dedicated public IPv4 address on our own network AS58269, which is exactly what a VPN endpoint needs. If the task is connecting whole offices rather than single devices, key distribution, monitoring and failover become the actual work; for that case we offer a managed site-to-site VPN, where we run and monitor the tunnels and you keep control of the routing.

Rather have us run it for you?
VPS. NVMe virtual servers, live in under a minute.
Learn more

Ready to start?

Deploy in minutes or talk to an engineer about what fits your project.