DEV Community

ricco020
ricco020

Posted on

Self-hosted WireGuard VPN on a VPS: a clean copy-paste quickstart

A self-hosted WireGuard VPN on a $5/month VPS gives you a private exit IP you fully control — no logs but your own, no shared IP pools, no monthly per-device fees. Here's a clean, copy-pasteable quickstart on Ubuntu. (For DNS hardening, a kill switch and multi-client management, see the full tutorial linked at the end.)

Prerequisites

  • A VPS with a public IPv4 (Contabo, Hetzner, OVH… any works), Ubuntu 22.04+ with root.
  • UDP 51820 reachable (open it in the provider firewall).

1. Install WireGuard

sudo apt update && sudo apt install -y wireguard
Enter fullscreen mode Exit fullscreen mode

On Linux 5.6+ WireGuard is a kernel module — minimal overhead, no userspace daemon.

2. Generate server keys

cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
Enter fullscreen mode Exit fullscreen mode

umask 077 matters: the private key must not be world-readable.

3. Server config — /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
PostUp   = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Enter fullscreen mode Exit fullscreen mode

Replace eth0 with your real public interface (ip route get 1.1.1.1 shows it).

4. Enable IP forwarding

echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wg.conf
sudo sysctl --system
Enter fullscreen mode Exit fullscreen mode

5. Bring it up (and on boot)

sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
Enter fullscreen mode Exit fullscreen mode

sudo wg show should now list the interface with its public key and listening port.

6. Add a client

Generate a keypair on the client (or server-side), then add a peer to wg0.conf:

[Peer]
PublicKey = <client public key>
AllowedIPs = 10.8.0.2/32
Enter fullscreen mode Exit fullscreen mode

Reload without dropping the tunnel:

sudo wg syncconf wg0 <(wg-quick strip wg0)
Enter fullscreen mode Exit fullscreen mode

Client config (wg0.conf on the device):

[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = <server public key>
Endpoint = <server public IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Enter fullscreen mode Exit fullscreen mode

AllowedIPs = 0.0.0.0/0 routes all traffic through the tunnel. PersistentKeepalive = 25 keeps NAT mappings alive on mobile networks.

7. Verify

# on the client, after wg-quick up:
curl -s https://ifconfig.me      # should return the VPS IP
Enter fullscreen mode Exit fullscreen mode

Also run a DNS-leak check in the browser — if your real resolver shows up, set DNS = in the client [Interface] (as above) and confirm.

Common gotchas

  • No traffic flows → wrong eth0 name in PostUp, or ip_forward not applied.
  • Works on Wi-Fi, drops on 4G → add PersistentKeepalive = 25 (above).
  • Handshake but no internet → MASQUERADE rule missing or wrong outbound interface.

Where to go next

This is the minimal working setup. For provider selection (price/jurisdiction), DNS hardening, a Linux kill switch with iptables, and managing several clients, here's a complete step-by-step guide:

Self-host a VPN on Contabo with WireGuard — full tutorial

Top comments (0)