If you manage more than one server, or you just got tired of exposing phpMyAdmin, a staging site, or your monitoring dashboard to the open internet, a VPN is the fix. WireGuard has become the default choice because it's fast, the config file fits on a napkin, and it's already in the Linux kernel on any modern distro. This guide walks through installing it on a SkyServer VPS, connecting a client, and the handful of things that trip people up on the first attempt.
Why Put a VPN in Front of Your Admin Tools
Most VPS attacks aren't clever — they're bots scanning every IP on the internet for open ports. If your database admin panel, Grafana dashboard, or internal API only accepts connections from inside a WireGuard tunnel, none of that scanning matters. You've effectively removed the attack surface instead of trying to defend it. It's also just convenient: once connected, your laptop behaves as if it's sitting on the VPS's private network, so you can reach services bound to 127.0.0.1 or an internal subnet without SSH tunneling every single time.
Before You Start
- A SkyServer VPS running Ubuntu 22.04/24.04, AlmaLinux 8/9, or Debian 11/12
- Root or sudo access over SSH
- One free UDP port (51820 is the WireGuard default, but you can pick anything)
- A client device — laptop, phone, or another server
Step 1: Install WireGuard on the Server
On Ubuntu/Debian:
sudo apt update
sudo apt install wireguard wireguard-tools -y
On AlmaLinux/Rocky:
sudo dnf install epel-release -y
sudo dnf install wireguard-tools -y
Step 2: Generate the Server Keys
WireGuard uses public-key pairs instead of passwords. Generate the server's pair and lock down the private key:
cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key
Keep server_private.key secret — it never leaves this box. You'll paste server_public.key into every client config.
Step 3: Write the Server Config
Create /etc/wireguard/wg0.conf:
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <paste server_private.key here>
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
[Peer]
# client 1 — added in Step 5
PublicKey = <client public key>
AllowedIPs = 10.10.0.2/32
Swap eth0 for whatever your VPS calls its main interface — check with ip route | grep default if you're not sure. 10.10.0.0/24 is just a private range for the VPN itself; it doesn't need to match anything else on your network.
Step 4: Turn On IP Forwarding
Without this, the VPS won't route traffic between the tunnel and the internet (needed if you want full-tunnel VPN, not just access to the VPS itself):
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
If you only want to reach services running on this one VPS — not route all your internet traffic through it — you can skip forwarding and drop the PostUp/PostDown NAT lines entirely. Just point AllowedIPs on the client at the VPN subnet instead of 0.0.0.0/0.
Step 5: Generate a Client Config
Run these on the client machine, or on the server if it's easier and you're copying keys over securely:
wg genkey | tee client_private.key | wg pubkey > client_public.key
Client config, saved as wg0.conf on the client:
[Interface]
PrivateKey = <client_private.key>
Address = 10.10.0.2/32
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 = 10.10.0.0/24 instead of 0.0.0.0/0 if you only want split-tunnel access to the VPS's private network, leaving your regular internet traffic alone. Add the client's public key and its 10.10.0.2/32 address as a [Peer] block back in the server's wg0.conf (Step 3).
Step 6: Open the Firewall and Start the Tunnel
Whichever firewall you're running — UFW, firewalld, or CSF — allow the UDP port:
# UFW
sudo ufw allow 51820/udp
# firewalld
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload
Then bring the interface up on the server:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
On the client, run wg-quick up wg0 (Linux) or import the config into the official WireGuard app (Windows, macOS, iOS, Android). For mobile, generate a QR code so you don't have to retype keys:
sudo apt install qrencode -y
qrencode -t ansiutf8 < client-wg0.conf
Step 7: Verify the Connection
sudo wg show
You want to see the peer listed with a recent latest handshake timestamp and a nonzero transfer count. From the client, ping the server's VPN address:
ping 10.10.0.1
If that responds, the tunnel is live.
Common Problems and Fixes
| Symptom | Likely Cause | Fix |
|---|---|---|
| No handshake at all | UDP 51820 blocked by firewall or provider | Re-check ufw/firewall-cmd rules and any network-level firewall on the VPS control panel |
| Handshake succeeds, but no internet through the tunnel | IP forwarding off, or NAT/MASQUERADE rule missing or pointing at the wrong interface | Confirm net.ipv4.ip_forward = 1 and that PostUp references your real outbound interface |
| Connects, but only reaches the VPS itself | Client's AllowedIPs is scoped to the VPN subnet only | Expected in split-tunnel mode — set to 0.0.0.0/0 for full tunnel |
| Works for a minute, then drops | NAT/router in front of the client is dropping idle UDP sessions | Keep PersistentKeepalive = 25 in the client config |
| DNS still resolves through your ISP | Client OS ignoring the DNS line in the config | On Linux, install resolvconf or systemd-resolved integration; on desktop apps this is usually automatic |
Locking It Down Further
- Give each device its own key pair — never share one private key across multiple clients. If a laptop is lost, you revoke just that peer.
- Restrict
AllowedIPsper peer as tightly as the use case allows. A monitoring server that only needs to poll one internal port doesn't need0.0.0.0/0. - If your VPS has a dynamic IP or you're connecting between multiple sites, pair the client
Endpointwith a small DDNS hostname instead of a raw IP. - Periodically run
wg showand prune peers you no longer recognize fromwg0.conf. - Combine this with SSH key-only login and fail2ban — WireGuard protects services behind it, but SSH itself is still worth hardening on its own.
Frequently Asked Questions
Is WireGuard better than OpenVPN for a VPS?
For most use cases, yes. WireGuard's codebase is a fraction of OpenVPN's size, it's built into the Linux kernel so there's less overhead, and setup is simpler because there's no certificate authority to manage — just key pairs. OpenVPN still has an edge in some corporate environments that require TCP-only traffic to get through restrictive firewalls, but for admin access to your own servers, WireGuard is the easier and faster choice.
Will running WireGuard slow down my VPS?
No, it's lightweight even on small VPS plans. The main cost is the encryption overhead on traffic passing through the tunnel, which is minimal on modern CPUs. You won't notice any impact on the services already running on the box.
Can I connect multiple devices to the same VPS?
Yes. Each device gets its own key pair and its own [Peer] block in the server config, with a unique address in the 10.10.0.0/24 range (or whatever subnet you chose). There's no practical limit for typical admin-access use cases.
Does this work if my VPS is behind CGNAT or my home internet is?
If the VPS has a public IP — which every SkyServer VPS does — clients connecting to it work fine regardless of what's happening on the client's end of the connection. CGNAT only becomes a problem if you're trying to reach a client from the server side, which isn't how this setup works.
Do I still need my firewall (UFW/CSF) if I set up WireGuard?
Yes — WireGuard secures one path in, it doesn't replace your firewall. Keep your firewall rules in place for the ports you intentionally expose (HTTP/HTTPS, SSH if you still allow direct access), and use the VPN specifically to hide the ports and services you don't want public at all.
