Guide

Run Your Own VPN on an Offshore VPS

Commercial VPNs ask you to trust a no-log policy written by their marketing department. Your own VPS has nothing to log but what you configure. Here is the full WireGuard setup — and an honest list of the tradeoffs.

Why self-hosted beats a commercial VPN

A commercial VPN's "no logs" is a policy. Your own VPS's no-logs is an architecture. That difference matters more than any audit badge:

  • A VPN provider sees everything by design. Thousands of users' traffic terminates on servers the company fully controls. A sealed order plus a quiet logging change is invisible to you — and has happened before, at providers you've heard of.
  • On your own VPS, you control the whole stack. Your sshd, your disk, your WireGuard config. We run nothing inside your guest and keep no activity or connection logs on the network side. We can't see into your VPS; a VPN company is defined by seeing into its tunnel.
  • Jurisdiction works for you. Your exit lives where you deploy it — outside the surveillance alliances if you choose, governed by the hosting jurisdiction's courts rather than a VPN company's home country.

And the honest counterweight: a self-hosted VPN has a dedicated IP that is yours alone. Websites won't flag it as a VPN (a genuine quality-of-life upgrade), but all your traffic shares one address — you are not blending into a crowd of thousands. If crowd anonymity is the requirement, use Tor. If trustworthy infrastructure is the requirement, nothing beats a box you control.

What we're building

Phone and laptop → WireGuard tunnel → an SV-Pro in your chosen location → the open internet. IPv4 forwarding with NAT on the server, full-tunnel routing on the clients (0.0.0.0/0), DNS via 9.9.9.9. Example server IP throughout: 185.220.101.14 — substitute yours. The base OS is Debian 13; if you haven't hardened the box yet, do the 30-minute checklist first, then come back.

Server setup on Debian 13

Install and generate keys

apt update && apt install -y wireguard qrencode

cd /etc/wireguard
umask 077

# server keypair
wg genkey | tee server.key | wg pubkey > server.pub

# one keypair per client device (laptop shown; repeat for phone)
wg genkey | tee laptop.key | wg pubkey > laptop.pub

Generating client keys on the server is acceptable for a first setup since you're transferring configs over SSH anyway. For stricter hygiene, generate keys on each device and paste only the public keys into the server config.

Write wg0.conf

# /etc/wireguard/wg0.conf
[Interface]
Address    = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
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

# laptop
[Peer]
PublicKey  = <contents of laptop.pub>
AllowedIPs = 10.10.0.2/32

# phone — repeat the block with 10.10.0.3/32

Check your uplink interface name with ip route | grep default — on VPSRento images it's eth0, but if yours differs, adjust the MASQUERADE lines.

Enable forwarding and start

# turn on IPv4 forwarding, persist across reboots
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf

# firewall: one UDP port, nothing else
ufw allow 51820/udp comment 'WireGuard'

# bring it up, now and on boot
systemctl enable --now wg-quick@wg0
wg show

wg show should print the interface, the listening port and your peers. No handshake lines yet — those appear when a client connects.

Client configuration

On the laptop, laptop.conf:

[Interface]
PrivateKey = <contents of laptop.key>
Address    = 10.10.0.2/32
DNS        = 9.9.9.9

[Peer]
PublicKey           = <contents of server.pub>
AllowedIPs          = 0.0.0.0/0, ::/0
Endpoint            = 185.220.101.14:51820
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0, ::/0 routes everything through the tunnel — change it to a split tunnel later if you ever want one. PersistentKeepalive keeps the path alive through home NAT. For the phone, don't type anything: generate the phone's config file on the server and render it as a QR code in your terminal:

# prints a scannable QR in the terminal — scan it with the WireGuard app
qrencode -t ansiutf8 < phone.conf

Activate, then verify from any client: curl ifconfig.me should answer with your VPS's IP, and a DNS leak test should show 9.9.9.9's operator — not your ISP.

Performance notes

WireGuard lives in the kernel and speaks ChaCha20 — on the AMD EPYC nodes, a single tunnel realistically moves 600–900 Mbps through NAT, which is to say it saturates the port long before it strains the CPU. The binding constraint is never the cipher; it's the plan's bandwidth terms. A VPN is bandwidth-pure: every gigabyte you download counts once inbound and once outbound. On metered plans that arithmetic matters. On the SV-Pro — $19.99/mo, unmetered at 1 Gbps — it doesn't, which is why the SV-Pro is the plan we point VPN builders at. One customer runs a full-family setup on a single SV-Pro in Amsterdam and has yet to find its ceiling.

Multi-hop: enter in Amsterdam, exit in Reykjavik

For a second layer, chain two VPSes across jurisdictions. Entry node in the Netherlands (cheap latency to you), WireGuard tunnel between the two servers, exit node in Iceland (the jurisdiction you actually want your traffic to originate from). Your devices see one endpoint in Amsterdam; the internet sees an IP in Reykjavik; the entry node sees only ciphertext passing through. Mechanically it's the same configs you just wrote, twice — a second wg interface on the entry node whose default route points at the exit tunnel. The cost is roughly 40–60ms of added latency and one more $5.99–6.89 VPS. Worth it when your threat model has a budget; decoration when it doesn't.

Honest limitations

  • You are the operator now. Updates, key rotation and uptime are yours. unattended-upgrades and the hardening checklist cover most of it; the rest is an occasional apt upgrade on a Sunday.
  • One IP is one identity. Observers can correlate everything exiting your address. When it matters, redeploy in another location — 55 seconds later you have a fresh exit and a fresh IP checked against 40+ blacklists.
  • A VPS is not Tor. This setup protects you from your ISP, from hostile Wi-Fi, and from VPN companies. Against a state-level adversary watching both ends of the tunnel, timing correlation exists. Know which fight you're in.

Your tunnel. Your logs: none.

SV-Pro — 4 vCPU, 8 GB RAM, unmetered 1 Gbps — is the VPN builders' pick at $19.99/mo. Root in 55 seconds.