Set Up a WireGuard VPN on Your VPS: Full Guide
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 wireguard
On AlmaLinux/Rocky (common on cPanel VPS boxes), use:
sudo dnf install -y epel-release elrepo-release
sudo dnf install -y kmod-wireguard wireguard-tools
Step 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.key
Then 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/32
Address 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 -p
Then 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 MASQUERADE
Open 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 -r
Step 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 = 25
Set 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 show
Import 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 peer
Then 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.
Frequently asked questions
Is it safe to run WireGuard on a VPS that already has CSF or UFW active?
Yes. WireGuard just needs its one UDP port explicitly allowed through whichever firewall you run. Keep every other port managed as normal — CSF and WireGuard don't conflict with each other.
Can I run WireGuard alongside cPanel on the same VPS?
Yes, WireGuard runs as its own kernel module and systemd service, independent of cPanel/WHM. Just make sure the UDP port you pick isn't already used by another service, and add the firewall rule through CSF instead of UFW since that's what cPanel VPS servers typically use.
Do I need a static IP on my VPS for this to work?
You need a public IP that doesn't change, which is what you get by default on a VPS. If your provider ever reassigns the IP, update the Endpoint line in every client config to match.
How many clients can one WireGuard server handle?
Comfortably dozens on a small VPS — WireGuard's overhead per peer is minimal. The bottleneck is usually your VPS's bandwidth and CPU for encryption, not the WireGuard protocol itself.
What if UDP port 51820 is blocked on a client's network?
Change ListenPort in wg0.conf (and the Endpoint port in the client config) to 443. Traffic on 443/UDP rarely gets blocked since it overlaps with QUIC/HTTP3, and WireGuard doesn't care which port number you pick.