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
| Provider | Location | Price | Notes |
|---|---|---|---|
| Vultr | Global | $3.50/mo | 100% SSD, fast network |
| Hetzner | EU | €3/mo | Great value, EU-friendly |
| DigitalOcean | Global | $5/mo | Easy setup, good docs |
| GCP F1-micro | us-central | Free | Limited, 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?
| Aspect | WireGuard | OpenVPN |
|---|---|---|
| Lines of code | ~4,000 | ~100,000 |
| Speed | Very fast (kernel-level) | Moderate |
| Security surface | Small, auditable | Larger attack surface |
| Mobile battery | Efficient keepalive | Drains battery faster |
| Setup complexity | Low | Medium |
| Protocol fingerprint | Distinctive (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.