Why run your own VPN
A commercial VPN asks you to trust one company's no-logs claim across thousands of users who share a handful of exit IPs. Self-hosting WireGuard on an offshore VPS flips that trust model: you hold the keys, you set the logging policy, and the only metadata that exists is the metadata you choose to keep. For some threat models that is the right trade — you stop trusting marketing copy and start trusting your own configuration plus the jurisdiction the server sits in.
WireGuard is the modern choice for the job. It is a few thousand lines of audited kernel code with a tiny attack surface next to OpenVPN or IPsec, and it ships fixed modern cryptography — Curve25519, ChaCha20-Poly1305, BLAKE2s — so there is no cipher suite to misconfigure into something weak. Handshakes are fast, roaming between Wi-Fi and mobile is seamless, and an idle tunnel costs almost nothing. On an offshore VPS you get a dedicated exit in a jurisdiction you pick from 6 regions, online in about 15 min, with the 1.5 Tbps L3/4 mitigation and an unmetered port standard on every plan.
SP·02What a self-hosted tunnel hides — and what it doesn't
Be honest about the model before you build it. A self-hosted tunnel encrypts everything between your device and the VPS, hiding it from your local network and ISP, and it replaces your home IP with the VPS IP for whatever you route through it. That is genuinely useful on hostile Wi-Fi, for reaching your own services behind a stable address, or for keeping your access ISP out of your browsing.
What it does not do is make you anonymous. The exit IP is yours alone — there is no crowd of other users to blend into, so anyone who can correlate both ends of the connection, or who obtains a binding order against the host, can attribute that address to your account. On the host side, the stance is fixed: DMCA notices are not processed or answered — the DMCA is a US statute with no force in our jurisdictions, and we act only on a binding order from a court with jurisdiction over the specific server. That protects you from automated takedown robots; it does not make a single-user VPN an anonymity tool. If your adversary is a global passive observer, reach for Tor instead. A self-hosted tunnel is a confidentiality and control tool, not a cloak.
SP·03Pick the location and plan first
A personal VPN is bandwidth-bound, not CPU-bound, so the smallest plan is plenty — the Drift VPS at $8.00/mo will saturate its port long before the vCPU breaks a sweat. Spend your decision budget on where instead. Put the server close to you when latency for interactive use matters, or far from you when legal distance matters more than round-trip time.
Romania and the Netherlands bill at base rate and carry the best European connectivity; Switzerland, Iceland, Malaysia and Panama apply a regional modifier shown live in the configurator. Malaysia is the Asia-Pacific pick; Panama and Iceland lean hardest toward jurisdictional distance. If you are unsure, the companion guide which offshore location should you pick? walks the trade-offs region by region. Whichever you choose, top up your balance from $30.00 with crypto and deploy — there is no identity check and no card on file.
SP·04How the pieces fit together
WireGuard models a VPN as a set of peers, each identified by a public key, talking over a virtual interface (here wg0). The server gets a private subnet — say 10.66.0.0/24 plus an IPv6 ULA — and each client takes one address inside it. The server's [Interface] block holds its private key and listen port; every client is a [Peer] block carrying that client's public key and the addresses it is allowed to use.
On the client side, AllowedIPs = 0.0.0.0/0, ::/0 is what makes this a full-tunnel VPN: it tells the client to route all traffic through wg0. The server then NATs that traffic out its real network interface with a masquerade rule, which is why IP forwarding has to be enabled in the kernel. PersistentKeepalive = 25 keeps the path open through stateful firewalls and carrier NAT. Set DNS on the client to a resolver you trust so lookups travel inside the tunnel rather than leaking to your local network. WireGuard itself is connectionless — there is no long-lived session to drop, so the link survives a sleeping laptop or a phone switching from Wi-Fi to mobile without any reconnect dance. If a path has an awkward MTU and large packets stall, lowering the client interface MTU to around 1380 usually clears it. Get those four ideas — interface, peers, AllowedIPs, masquerade — and the config below reads like prose.
Harden the server while you're there
A VPN endpoint is worth locking down. Move SSH to key-only authentication and disable password and root logins in /etc/ssh/sshd_config (PasswordAuthentication no, PermitRootLogin prohibit-password), then reload sshd. Keep the firewall default-deny: the only inbound ports a WireGuard box needs are SSH and UDP 51820. Everything else stays closed.
Keep the WireGuard key files at 0600 — the umask 077 in the steps below handles that — and never copy a private key off the host it belongs to. Turn on unattended security updates so the kernel and wireguard package stay patched without a babysitter. Test for DNS leaks once the tunnel is up — a lookup that resolves through your chosen resolver, not your access ISP, confirms queries really are staying inside wg0. If you expose other services later, add fail2ban and per-service rules rather than widening the firewall. None of this depends on the host: the VPS is yours, root is yours, and the 99.9% uptime commitment keeps the box reachable so your tunnel stays up.
Add more devices and keep it running
Every device that connects needs its own keypair and its own [Peer] block on the server, each with a unique address inside the subnet — reusing one keypair across a laptop and a phone breaks roaming and muddies any troubleshooting. Generate a fresh client2.key/client2.pub pair, append a peer, and either reload the interface with wg syncconf wg0 <(wg-quick strip wg0) or bounce it with systemctl restart wg-quick@wg0.
For phones, skip the file copy entirely: render the client config as a QR code on the server with qrencode -t ansiutf8 < client.conf and scan it straight into the official WireGuard app. To see who is connected and when each peer last handshaked, run wg show — it is the whole monitoring story for a personal deployment. Snapshots before a kernel upgrade give you a clean rollback if a new release ever misbehaves.
When a commercial VPN or Tor is the better tool
Self-hosting is not always the answer, and pretending otherwise would be dishonest. If your goal is to disappear into a crowd, a reputable multi-user VPN gives you shared exit IPs that many people use at once — a single-tenant tunnel cannot offer that. If you need to hop between exit countries on demand, a commercial service with a click-to-switch app is simply more convenient than spinning up boxes. And if you need genuine anonymity against a well-resourced adversary, Tor's onion routing is designed for exactly the correlation problem a self-hosted VPN cannot solve.
Where self-hosting wins is control and confidentiality: you are not trusting anyone else's logging policy, you get a stable dedicated IP for admin and allowlists, and you decide the jurisdiction. Many people run both — a self-hosted tunnel for everyday confidentiality and Tor for the rare task that demands anonymity. Pick the tool that matches the threat, not the one with the best landing page.
SP·08Step by step
-
01
Deploy the VPS and install WireGuard
Deploy a VPS with Debian 13 or Ubuntu 24.04, sign in as root over SSH, then update and install the two packages you need.
apt update && apt full-upgrade -y apt install -y wireguard qrencode
-
02
Enable IP forwarding
A full-tunnel VPN forwards client traffic out the server's interface, so the kernel must allow forwarding for IPv4 and IPv6.
cat > /etc/sysctl.d/99-wg.conf <<'EOF' net.ipv4.ip_forward=1 net.ipv6.conf.all.forwarding=1 EOF sysctl --system
-
03
Generate the server keys
Work in
/etc/wireguardwith a tight umask so every key file lands at0600.cd /etc/wireguard umask 077 wg genkey | tee server.key | wg pubkey > server.pub
-
04
Generate a client keypair
Each device gets its own keypair. Make the first one now.
wg genkey | tee client.key | wg pubkey > client.pub
-
05
Write the server config
Find your real network interface with
ip route get 1.1.1.1and replaceeth0below if it differs (it is oftenenp1s0). The$(cat ...)calls inline the keys you just made.cat > /etc/wireguard/wg0.conf <<EOF [Interface] Address = 10.66.0.1/24, fd86:ea04:1115::1/64 ListenPort = 51820 PrivateKey = $(cat server.key) PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = $(cat client.pub) AllowedIPs = 10.66.0.2/32, fd86:ea04:1115::2/128 EOF
-
06
Write the client config
Create
client.confin the same directory. Paste the contents ofclient.keyandserver.pubwhere shown, and setEndpointto your server's public IP.AllowedIPs = 0.0.0.0/0, ::/0routes everything through the tunnel.[Interface] PrivateKey = <paste client.key> Address = 10.66.0.2/32, fd86:ea04:1115::2/128 DNS = 9.9.9.9 [Peer] PublicKey = <paste server.pub> Endpoint = YOUR_SERVER_IP:51820 AllowedIPs = 0.0.0.0/0, ::/0 PersistentKeepalive = 25
-
07
Open the firewall
Allow SSH and the WireGuard UDP port, then enable
ufw. Keep the default-deny posture for everything else.ufw allow OpenSSH ufw allow 51820/udp ufw enable
-
08
Bring the tunnel up
Enable the interface so it survives reboots, then confirm peers and handshakes.
systemctl enable --now wg-quick@wg0 wg show
-
09
Connect a phone with a QR code
Render the client config as a scannable code and import it into the WireGuard mobile app — no file transfer needed.
qrencode -t ansiutf8 < client.conf

