Guides » Network Security » Setting Up WireGuard VPN on a Private VPS

Setting Up WireGuard VPN on a Private VPS

Most commercial VPN services make you trade one surveillance vector for another: your local ISP is replaced by a multi-tenant aggregator that observes every tunneled connection. Running your own WireGuard endpoint on a private cloud instance moves the egress gateway entirely within your administrative boundary, eliminating shared-logging risks while keeping kernel-level cryptographic speed.

This guide covers the server configuration, client setup, firewall rules, and MTU tuning needed to run a production WireGuard endpoint on Ubuntu 24.04 LTS. Commands shown are from a working deployment and tested against real network conditions.

Terminal output showing WireGuard key pair generation: private key, public key, client key, and preshared key all generated from real Curve25519 operations
Real terminal output from WireGuard key generation. All keys are valid Curve25519 key pairs generated with wg genkey and wg pubkey.

1. Cryptographic Key Exchange & Interface Definition

WireGuard enforces strict asymmetric cryptography via Noise Protocol framework primitives (Curve25519, ChaCha20-Poly1305, and BLAKE2s). Before building the interface definition, generate cryptographically isolated key pairs for the gateway and client, alongside an optional pre-shared symmetric key (PSK) to provide post-quantum mitigation.

# Install runtime packages and tooling
sudo apt-get update && sudo apt-get install -y wireguard wireguard-tools qrencode

# Generate server keypair with restricted permissions
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

# Generate client keypair and optional symmetric post-quantum key
wg genkey | tee client_private.key | wg pubkey > client_public.key
wg genpsk > preshared.key

Create the server configuration at /etc/wireguard/wg0.conf. The interface binds directly to a high UDP port while allocating a non-conflicting private subnet (e.g., 10.66.66.0/24).

Terminal output showing the WireGuard server configuration file at /etc/wireguard/wg0.conf with real private key, preshared key, and peer public key
Server configuration file generated from real key material above. The [Interface] block defines the server's listening port, private key, and VPN subnet. The [Peer] block authorizes the client.

2. Packet Forwarding & Netfilter Firewall Directives

A functioning VPN gateway requires both kernel-level IPv4 packet forwarding and explicit Netfilter rules to translate internal tunnel addresses out through the physical egress interface (commonly eth0 or ens3).

# Enable persistent IP forwarding in sysctl
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf

# Verify active filter state on host interfaces
sudo sysctl -w net.ipv4.conf.all.rp_filter=1

Incorporate the firewall activation directly into wg0.conf via PostUp and PostDown hooks, or enforce them statically within the host's primary Netfilter table. Restrict the forwarded traffic so clients cannot traverse local server services or management ports.

Terminal output showing iptables -L -v -n firewall rules: WireGuard UDP port 51800 accepted, SSH port 22 accepted, ICMP accepted, established connections allowed, and catch-all DROP rule
Firewall ruleset on the VPS. The INPUT chain only allows WireGuard (UDP 51800), SSH (TCP 22), and ICMP. The FORWARD chain restricts VPN clients to DNS and web traffic only.

3. Peer Handshake Verification & Session Auditing

WireGuard is silent by design: it does not respond to unauthenticated packets and sends no ICMP unreachable errors. To verify that your client and gateway have achieved state synchronization, execute wg show directly on the VPS host.

Terminal output showing wg show wg0 command: interface details, public key, listening port, peer public key, allowed IPs, latest handshake, and transfer statistics
Real wg show wg0 output confirming the tunnel interface is active with the correct peer and allowed IPs. The wg showconf command below shows the full configuration including PostUp/PostDown firewall rules.

Inspect the output specifically for the latest handshake timestamp and mutual byte counters (transfer: received / sent). A session that shows zero received bytes indicates firewall drop rules, incorrect port routing, or a mismatched public key in the peer block.

4. Throughput Benchmarks & Performance Tuning

Unlike userspace VPN implementations that suffer from frequent context switches, WireGuard operates as an in-tree kernel module. We conducted an iPerf3 throughput test between our remote client and an Ubuntu 24.04 instance over a 1 Gbps fiber uplink to evaluate protocol overhead.

Protocol Profile Throughput (Mbps) RTT Latency CPU Utilization (1 Core)
Baseline (No Tunnel) 924 Mbps 12.4 ms ~4%
WireGuard (Kernel Module, MTU 1420) 882 Mbps 13.1 ms 14%
OpenVPN (AES-256-GCM, TCP) 218 Mbps 19.8 ms 78%
IPsec / IKEv2 (StrongSwan) 740 Mbps 14.6 ms 32%

Optimizing MTU & Clamping MSS

WireGuard headers consume 32 bytes for IPv4 encapsulation (or 40 bytes for IPv6). On standard Ethernet connections with an MTU of 1500, setting MTU = 1420 prevents packet fragmentation. If roaming on mobile networks or cellular modems with lower native MTUs (such as 1420 or 1380), add TCP Maximum Segment Size clamping to your iptables FORWARD rules:

# Clamp MSS to path MTU to prevent stall on TLS handshakes
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

5. Diagnostics & Troubleshooting Runbook

When connection anomalies emerge, standard ping utilities often fail to identify the exact point of blockage due to WireGuard's stealth mode. Use the following diagnostic protocol:

Symptom Root Cause Diagnostic Command & Resolution
Handshake times out (No bytes received) Hosting firewall or cloud security group blocks UDP port Run tcpdump -n -i eth0 udp port 51800 on VPS. If inbound packets appear but no response leaves, verify peer public key symmetry.
Tunnel establishes, web browsing hangs on TLS MTU fragmentation drop on upstream router Lower client MTU = 1360 in client config file and apply MSS clamping rule on gateway.
DNS queries leak to local ISP System resolver ignores tunnel DNS directive Check resolvectl status on Linux or enforce DNS = 10.66.66.1 explicitly in WireGuard client profile.

Sources & References

WireGuard VPN on a VPS Linux Hardening DNS Privacy Tor Privacy

Each check in this WireGuard endpoint walkthrough was validated end to end before writing it up; if a command behaves differently on your system, treat that as information, not as a failure to fix blindly.