Skip to main content
· Networking · 4 min read

Self-Hosted VPN: WireGuard on a $5 VPS for Privacy and Remote Access

Commercial VPNs charge $5-15/month and have the logs to prove you’re using them. A self-hosted WireGuard VPN on a $5 VPS does the same thing — routes your traffic through a server in another region — but you control the infrastructure and the data. No logs, no subscription, no trust required.

The Architecture

%%{ init: { 'look': 'handDrawn' } }%%
graph LR
    A[Laptop / Phone<br/>WireGuard client] -->|UDP 51820<br/>encrypted tunnel| B[VPS<br/>WireGuard server<br/>Oregon, US]
    B -->|unrestricted<br/>internet| C[Streaming services<br/>Google<br/>Regional content]
    B -->|private<br/>access| D[Home network<br/>192.168.1.0/24]

WireGuard is the modern VPN protocol: ~4,000 lines of code (vs OpenVPN’s ~100,000), constant-time cryptographic handshakes, and native kernel integration on Linux. It uses Curve25519 for key exchange, ChaCha20-Poly1305 for encryption, and BLAKE2s for hashing.

VPS Providers

ProviderLocationPriceNotes
VultrGlobal$3.50/mo100% SSD, fast network
HetznerEU€3/moGreat value, EU-friendly
DigitalOceanGlobal$5/moEasy setup, good docs
GCP F1-microus-centralFreeLimited, good for testing

Any of these work. The key is choosing a region close to the content you want to access.

Server Setup

# On the VPS — install wireguard
apt update && apt install -y wireguard

# Generate server keys
wg genkey | tee server_private.key | wg pubkey > server_public.key

# Generate client keys (do this on your laptop, then share public key)
wg genkey | tee client_private.key | wg pubkey > client_public.key

Server Configuration

# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <server_private_key>
Address = 10.0.0.1/24
ListenPort = 51820
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]
PublicKey = <client_public_key>
AllowedIPs = 10.0.0.2/32

PostUp/PostDown handle NAT so VPN clients can reach the internet through the VPS. AllowedIPs restricts each peer to a specific IP in the VPN subnet.

Client Configuration

# Client (laptop/phone)
[Interface]
PrivateKey = <client_private_key>
Address = 10.0.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public_key>
Endpoint = your-vps-ip:51820
AllowedIPs = 0.0.0.0/0  # Route ALL traffic through VPN
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0 routes everything through the VPN — including your DNS queries. DNS = 1.1.1.1 ensures DNS also goes through the tunnel, preventing DNS leaks.

For split tunnel (only route specific traffic through VPN):

AllowedIPs = 10.0.0.0/24  # Only VPN subnet
AllowedIPs = 192.168.1.0/24  # Home network access

Enable IP Forwarding

# /etc/sysctl.conf
net.ipv4.ip_forward = 1

# Apply immediately
sysctl -p

Without IP forwarding, the VPS can’t forward VPN traffic to the internet.

Start the Service

systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

Mobile Setup with QR Code

# Generate QR code for mobile (on server)
apt install -y qrencode
qrencode -t ansiutf8 < /etc/wireguard/wg0.conf

Scan it with the WireGuard app on iOS or Android. That’s it — mobile config in 30 seconds.

Traffic Flow Summary

%%{ init: { 'look': 'handDrawn' } }%%
graph TD
    A[Laptop] -->|Encrypted UDP<br/>WireGuard| B[VPS:51820]
    B -->|NAT + forward| C[Internet]
    A -->|DNS query<br/>1.1.1.1| B
    B -->|Forwarded<br/>DNS| C
    A -->|Access<br/>home LAN| D[Home NAS<br/>192.168.1.50]
    B -->|Forwarded to<br/>10.0.0.2| D

Why Not OpenVPN?

AspectWireGuardOpenVPN
Lines of code~4,000~100,000
SpeedVery fast (kernel-level)Moderate
Security surfaceSmall, auditableLarger attack surface
Mobile batteryEfficient keepaliveDrains battery faster
Setup complexityLowMedium
Protocol fingerprintDistinctive (can be blocked)Looks like HTTPS

WireGuard wins on almost every dimension. The only downside is that it’s relatively new and its protocol is easy to fingerprint and block in restrictive network environments.

When to Route Everything vs. Split Tunnel

Route everything (AllowedIPs = 0.0.0.0/0):

  • Untrusted public WiFi
  • Bypassing regional restrictions
  • Maximum privacy

Split tunnel (AllowedIPs = 10.0.0.0/24, 192.168.1.0/24):

  • Only need remote network access
  • Want to preserve local network for printing/local services
  • Lower bandwidth usage

The key advantage of self-hosting: you know exactly who’s on your VPN (because you control it), no bandwidth caps, and no third-party logging. Commercial VPNs are convenient but you’re trusting them with your traffic patterns.

One variation worth knowing: if what you actually want is reaching your own network rather than exiting in another region, run the same WireGuard config on a Raspberry Pi at home instead of a VPS. Identical protocol, identical client config — you just point the endpoint at your house and skip the monthly bill entirely.