WireGuard is a modern VPN protocol that uses state-of-the-art cryptography and fits in under 4,000 lines of kernel code. Unlike OpenVPN or IPsec, WireGuard is designed for simplicity: a single configuration file per peer, no certificate authorities, and no connection daemon to manage. This guide covers deploying WireGuard on a VPS as a remote access VPN, configuring clients on Linux, macOS, and Windows, and setting up site-to-site networking between multiple VPS instances.
Why WireGuard for VPS Access?
Every VPS exposes at least one public service (SSH, web server, database). Reducing the attack surface by restricting access to a VPN is a fundamental security practice. WireGuard is ideal for this because:
- Minimal attack surface: WireGuard does not accept connections until a peer is configured with the correct public key. There is no authentication daemon, no handshake protocol for unauthorized clients, and no logging of failed attempts.
- Kernel-level performance: On Linux, WireGuard runs as a kernel module (built into kernel 5.6+), meaning encryption and encapsulation happen at the network stack layer with negligible overhead.
- Roaming support: WireGuard handles IP address changes transparently. A laptop moving from Wi-Fi to cellular does not drop the VPN connection.
- Cryptographic soundness: WireGuard uses Curve25519 for key exchange, ChaCha20 for encryption, and Poly1305 for authentication — all modern, well-audited primitives.
Installation
Server (VPS) Installation
# Ubuntu/Debian
sudo apt update
sudo apt install wireguard wireguard-tools
# Verify the kernel module is loaded
sudo modprobe wireguard
lsmod | grep wireguard
Client Installation
- Linux:
sudo apt install wireguard-tools - macOS:
brew install wireguard-toolsor use the official macOS app from the App Store. - Windows: Download the official WireGuard installer from wireguard.com/install.
- Android/iOS: Official apps are available on the Play Store and App Store.
Key Generation
WireGuard uses Curve25519 key pairs. Generate a key pair for the server and each client:
# Generate private key (keep this secret!)
wg genkey | sudo tee /etc/wireguard/server.key
sudo chmod 600 /etc/wireguard/server.key
# Derive the public key from the private key
sudo cat /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub
# On each client, generate a key pair the same way
wg genkey | tee client1.key
cat client1.key | wg pubkey | tee client1.pub
Store the private key securely on the device where it was generated. The public key is safe to share — it is the WireGuard equivalent of an account number.
Server Configuration
Create the server configuration file at /etc/wireguard/wg0.conf. This example sets up a remote access VPN with the VPS as the hub:
[Interface]
# Server's internal VPN IP address (choose a /24 subnet)
Address = 10.0.0.1/24
# Port WireGuard listens on (default: 51820)
ListenPort = 51820
# Server's private key
PrivateKey = <SERVER_PRIVATE_KEY>
# Enable IP forwarding (required for clients to access the internet through the VPS)
# Also set sysctl: net.ipv4.ip_forward = 1
# Client 1: Laptop
[Peer]
# Client 1's public key
PublicKey = <CLIENT1_PUBLIC_KEY>
# Client 1's allowed IPs (the IP address assigned to this client)
AllowedIPs = 10.0.0.2/32
# Client 2: Mobile phone
[Peer]
PublicKey = <CLIENT2_PUBLIC_KEY>
AllowedIPs = 10.0.0.3/32
# Client 3: Remote server (site-to-site)
[Peer]
PublicKey = <CLIENT3_PUBLIC_KEY>
AllowedIPs = 10.0.0.4/32, 192.168.1.0/24
Enable IP forwarding on the server so clients can route traffic through the VPS:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-wireguard-forwarding.conf
sudo sysctl --system
# Optional: NAT traffic from the VPN subnet to the internet
# (if clients should use the VPS as their internet gateway)
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
Start the WireGuard Interface
# Start the interface
sudo wg-quick up wg0
# Verify the interface is up
sudo wg show
# Enable the service to start on boot
sudo systemctl enable wg-quick@wg0
# You should see output like:
# interface: wg0
# public key: <SERVER_PUBLIC_KEY>
# private key: (hidden)
# listening port: 51820
#
# peer: <CLIENT1_PUBLIC_KEY>
# endpoint: (none yet, waits for client to connect)
# allowed ips: 10.0.0.2/32
Client Configuration
Linux Client
Create /etc/wireguard/wg0.conf on the client:
[Interface]
# Client's internal VPN IP
Address = 10.0.0.2/32
# Client's private key
PrivateKey = <CLIENT1_PRIVATE_KEY>
# DNS server (optional, routes DNS through the VPN)
DNS = 1.1.1.1
[Peer]
# Server's public key
PublicKey = <SERVER_PUBLIC_KEY>
# Server's public IP and WireGuard port
Endpoint = YOUR_VPS_IP:51820
# Allowed IPs: 0.0.0.0/0 routes ALL traffic through the VPN (full tunnel)
# 10.0.0.0/24 routes only VPN subnet traffic (split tunnel)
AllowedIPs = 0.0.0.0/0, ::/0
# Send a keepalive every 25 seconds (useful behind NAT)
PersistentKeepalive = 25
Start the client:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0
macOS and Windows Clients
Use the official WireGuard GUI applications. Create a new tunnel with the same configuration as the Linux client above. The GUI allows importing the configuration from a file or pasting it directly. The AllowedIPs setting determines whether the tunnel is full-tunnel (all traffic through the VPS) or split-tunnel (only VPN subnet traffic).
Firewall Configuration
WireGuard uses UDP. Ensure your VPS firewall allows inbound UDP traffic on port 51820:
# If using ufw
sudo ufw allow 51820/udp
# If using iptables directly
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
# If using nftables
sudo nft add rule inet filter input udp dport 51820 accept
Site-to-Site VPN: Connecting Two VPS Instances
WireGuard is also excellent for connecting multiple VPS instances in a private mesh network. This is useful for database replication, service discovery, or distributed application backends that should not communicate over the public internet.
For a site-to-site connection between VPS-A (10.0.0.1) and VPS-B (10.0.0.2):
VPS-A configuration (additional peer):
[Peer]
# VPS-B's public key
PublicKey = <VPS_B_PUBLIC_KEY>
# VPS-B's VPN IP and any subnets behind VPS-B
AllowedIPs = 10.0.0.2/32, 10.10.0.0/16
# VPS-B's public IP and WireGuard port
Endpoint = VPS_B_PUBLIC_IP:51820
# Both servers are always online, no keepalive needed
PersistentKeepalive = 0
VPS-B configuration (additional peer):
[Peer]
# VPS-A's public key
PublicKey = <VPS_A_PUBLIC_KEY>
# VPS-A's VPN IP and any subnets behind VPS-A
AllowedIPs = 10.0.0.1/32, 10.20.0.0/16
# VPS-A's public IP and WireGuard port
Endpoint = VPS_A_PUBLIC_IP:51820
PersistentKeepalive = 0
After both configurations are active, VPS-A and VPS-B can communicate over the VPN using their private IP addresses (10.0.0.1 and 10.0.0.2). Add routing rules on each VPS to direct traffic bound for the other’s subnet through the WireGuard interface.
Performance Tuning
WireGuard adds minimal overhead. For maximum throughput:
- MTU tuning: The default WireGuard MTU is 1420 bytes (subtracting 80 bytes for the WireGuard header from the standard 1500 byte Ethernet MTU). If your VPS uses a different underlying MTU (e.g., 1450 for PPPoE, 1400 for some VPN providers), adjust with
MTU = 1320in the[Interface]section. - Multi-queue support: WireGuard supports multiple encryption threads on multi-core systems. Increase the number of worker queues with
wg set wg0 fwmark 0xca6cif you need to saturate a 10 Gbps link. - Kernel module vs. userspace: The kernel module (built into Linux 5.6+) is significantly faster than userspace implementations. On older kernels, install the module via DKMS.
Security Hardening
- Restrict SSH to the VPN subnet: After WireGuard is working, modify your SSH server configuration to only listen on the VPN IP address (
ListenAddress 10.0.0.1in/etc/ssh/sshd_config). This means SSH is only accessible when connected to the VPN. - Use a non-standard WireGuard port: Changing the
ListenPortfrom 51820 to a random high port reduces automated scanning. - Rotate keys periodically: Generate new key pairs and update configurations monthly for high-security environments.
- Audit peer connections: Regularly run
sudo wg showto verify only expected peers are connected.
Troubleshooting
- No handshake: Verify the firewall allows UDP on port 51820. Check that the server’s public key matches the client’s Peer configuration. Confirm the client’s public key is in the server’s configuration.
- Can ping VPN IP but not the internet: Check that IP forwarding is enabled on the server and that the NAT masquerade rule is in place.
- DNS leaks: If using a split tunnel, ensure DNS queries are routed through the VPN by setting the
DNSfield in the client configuration. - Slow throughput: Check MTU settings. Run
ping -M do -s 1420 YOUR_VPS_IPto find the maximum MTU without fragmentation.
WireGuard transforms a VPS from a public-facing server into a private network hub. When selecting a VPS provider for your VPN and application servers, compare VPS providers on our comparison table to find instances with sufficient network throughput and the ability to add additional public IP addresses if needed. A $5/month VPS is more than sufficient for a WireGuard VPN serving 10–20 clients with full-tunnel throughput up to 200 Mbps.

Leave a Reply
You must be logged in to post a comment.