If you need a private, encrypted way into your VPS — for your own laptop, a remote dev environment, or a small team that shouldn't be poking at your database over the open internet — a self-hosted WireGuard VPN is one of the fastest things you can stand up. It's leaner than OpenVPN, ships in most modern Linux kernels already, and a working single-server setup takes about fifteen minutes if you follow the steps in order.
Why Run Your Own VPN on a VPS
WireGuard isn't trying to be a full corporate VPN suite. It's a point-to-point encrypted tunnel: a handful of config lines on the server, a matching handful on each client, and a public/private keypair instead of usernames and passwords. That simplicity is the whole appeal. Common reasons people put it on a VPS:
- Lock down MySQL, Redis, or an admin panel to only be reachable over the tunnel, instead of opening those ports to the world.
- Give a small team a shared private network between servers in different regions or providers.
- Route your own traffic through a fixed IP when a service whitelists by IP address.
- Reach internal dashboards (Netdata, phpMyAdmin, a staging site) without exposing them publicly.
Before You Start
You'll need:
- Root or sudo access on the VPS (Ubuntu 20.04+ or Debian 11+ — commands below assume apt).
- A public IP on the VPS (this is the default for Getwebup VPS plans).
- One UDP port free — 51820 is the WireGuard default, but any unused UDP port works.
- About 15 minutes and one other device (laptop or phone) to act as the client.
Step 1 — Install WireGuard
On Ubuntu/Debian, WireGuard is in the default repos, so this is a single command:
sudo apt update
sudo apt install -y wireguardOn AlmaLinux/Rocky (common on cPanel VPS boxes), use:
sudo dnf install -y epel-release elrepo-release
sudo dnf install -y kmod-wireguard wireguard-toolsStep 2 — Generate Server and Client Keys
Every WireGuard peer — server and client — has its own private/public keypair. Generate the server's pair first:
cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.keyThen generate a keypair for your first client the same way, just naming the files differently (e.g. client1_private.key / client1_public.key). You can do this on the client device itself if it also has wireguard-tools installed — the private key never needs to leave the machine it belongs to.
Step 3 — Configure the Server
Create /etc/wireguard/wg0.conf:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <paste server_private.key here>
SaveConfig = false
[Peer]
PublicKey = <paste client1_public.key here>
AllowedIPs = 10.8.0.2/32Address is the VPN's private subnet — 10.8.0.0/24 is a safe, unused default. Each client gets its own /32 address inside it (10.8.0.2, 10.8.0.3, and so on) via a matching [Peer] block.
Step 4 — Open the Firewall and Enable IP Forwarding
If clients need to reach the wider internet (not just the VPS itself) through the tunnel, turn on IP forwarding:
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -pThen add NAT and forwarding rules to the interface config so traffic actually routes out through the VPS's main network interface (replace eth0 with your actual interface, check it with ip a):
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <server private 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 MASQUERADEOpen the UDP port in whichever firewall you're running:
# UFW
sudo ufw allow 51820/udp
# CSF (common on cPanel/WHM VPS servers)
# Add 51820 to TCP_IN / UDP_IN in /etc/csf/csf.conf, then:
sudo csf -rStep 5 — Configure the Client
On the client device, create a matching config — call it getwebup-vpn.conf:
[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.address:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25Set AllowedIPs to 0.0.0.0/0 if you want all client traffic routed through the VPN. If you only need access to the VPS's private network (say, to reach an internal database), scope it down to just 10.8.0.0/24 instead — that's the safer default when you don't actually need full-tunnel routing.
Step 6 — Start the Tunnel and Test It
On the server:
sudo systemctl enable --now wg-quick@wg0
sudo wg showImport the client config into the WireGuard app (available for Windows, macOS, Linux, iOS, and Android), connect, then confirm the handshake happened:
sudo wg show
# look for a recent "latest handshake" timestamp under the peerThen ping the server's VPN address from the client (ping 10.8.0.1) to confirm the tunnel is actually passing traffic, not just showing a handshake.
Common WireGuard Problems
| Symptom | Likely Cause | Fix |
|---|---|---|
| Handshake never completes | UDP port blocked by firewall, or wrong public key pasted somewhere | Confirm ufw status / CSF rules allow the port; double-check server and client public keys are swapped correctly (server's public key goes in the client config, not the other way round) |
| Handshake works, but no internet through the tunnel | IP forwarding disabled, or missing MASQUERADE rule | Re-check sysctl net.ipv4.ip_forward returns 1, and that PostUp/PostDown rules reference the correct outbound interface |
| Works over Wi-Fi but not mobile data | Carrier NAT or firewall blocking outbound UDP on that port | Try switching the ListenPort to 443/UDP, which is rarely blocked |
| Connects, but internal hostnames don't resolve | No DNS server set in the client's [Interface] block | Add a DNS = line pointing at a resolver reachable through the tunnel |
| wg-quick@wg0 fails to start after reboot | Typo in wg0.conf, or the interface name conflicts with an existing one | Run sudo wg-quick up wg0 manually to see the actual error, and validate the config with wg-quick strip wg0 |
Hardening and Prevention Tips
- Give every client its own keypair and its own
/32address — never share one config across multiple devices. It makes revoking a lost laptop a one-line edit instead of a full key rotation. - Scope
AllowedIPsper peer as tight as the use case allows. A client that only needs the internal database doesn't need full-tunnel routing. - Remove a peer's block from
wg0.confand runsudo wg syncconf wg0 <(wg-quick strip wg0)to kick it off immediately without restarting the whole interface. - Keep the kernel and
wireguard-toolspackage updated — WireGuard's codebase is small and gets far less CVE churn than OpenVPN, but the surrounding tooling still needs patching. - If you're already running CSF or another IDS on the box, make sure the WireGuard UDP port is explicitly allowed rather than opened as a blanket rule — it should be the only thing listening on it.