Terminal showing a WireGuard wg0.conf interface and peer block on a no-KYC VPS
Self-hosted VPN guide

Set up a WireGuard VPS — your own VPN in minutes

A WireGuard VPS is a virtual server you control that runs the WireGuard kernel VPN, giving you a dedicated exit IP no commercial provider can log. On a no-KYC VPS you provision in about 47 seconds with an S1 plan from $5/mo, install WireGuard with three packages, generate keys with wg genkey, and route all traffic out one server. You hold the only keys.

Commercial VPNs ask you to trust a marketing page. A self-hosted VPN replaces that trust with control: you own the server, you generate the keys, you set the logging policy (none), and the exit IP belongs to you alone instead of a shared pool flagged by every fraud-detection vendor. WireGuard makes this practical — it is roughly 4,000 lines of code, lives in the Linux kernel since 5.6, and a working tunnel is a dozen lines of config.

This guide builds a complete WireGuard server on a no-KYC VPS, paid in Monero (XMR) with no ID, no phone, and no email verification. You will provision the box, harden the network with IP forwarding and nftables NAT, write the server and client configs by hand so you understand every line, add peers for your laptop and phone, and wire a kill-switch so nothing leaks if the tunnel drops.

Why WireGuard, and why your own server

Three VPN options exist: a commercial VPN, OpenVPN on your own box, or WireGuard on your own box. The third wins for most privacy-literate users.

WireGuard vs OpenVPN

  • Codebase: WireGuard is about 4,000 lines and auditable in an afternoon. OpenVPN plus its OpenSSL dependency is well over 100,000 lines — a far larger attack surface.
  • Crypto: WireGuard ships one fixed, modern suite (Curve25519, ChaCha20-Poly1305, BLAKE2s). There is no cipher negotiation, so there is no weak-cipher downgrade to misconfigure. OpenVPN's flexibility is also its footgun.
  • Speed: WireGuard runs in the kernel and handshakes in one round trip. On a modest VPS it saturates 1 Gbps; OpenVPN in userspace typically caps far lower on the same hardware.
  • Roaming: WireGuard is connectionless (UDP). Switch from Wi-Fi to LTE and the tunnel just continues — ideal for a phone.

Self-hosted vs commercial VPN

A commercial VPN sells you a slot in a shared IP pool that thousands of others — including abusers — also use. Those pools are pre-flagged by streaming services, banks, and fraud vendors, and you are trusting an unverifiable "no-logs" claim. A self-hosted WireGuard exit gives you a clean, dedicated IP that nobody else touches, a logging policy you set to zero, and keys only you hold. The tradeoff: the IP is obviously a single static address, so it is excellent for a private exit and terrible for blending into a crowd. For anonymity-in-numbers, layer Tor on top. See self-hosted VPN use cases for which job fits which tool.

Provision a no-KYC VPS for the exit

Pick the region closest to where you want your apparent location to be. NoKycVPS runs identical AMD EPYC hardware in Reykjavik (REK), Zurich (ZRH), Bucharest (OTP), and Paris (PAR). For a personal VPN the S1 plan (2 vCPU / 4 GB DDR5 / 80 GB NVMe Gen5, from $5/mo) is more than enough — WireGuard is so light that CPU is rarely the bottleneck before the 1 Gbps link is.

  • Account: email + password, that's the whole credential. No ID, no phone, no email verification, no captcha. A disposable email is fine.
  • Pay: top up your balance with Monero (XMR) — it credits in about 30 seconds — or any of the 10 supported coins. Deploys then debit the balance. At a $100 top-up you get a +30% bonus.
  • Image: choose Debian 13 or Ubuntu 24.04. Both ship a kernel with the WireGuard module built in.
  • Deploy: median build time is about 47 seconds. You get root and a clean IP.

If you would rather not type a single command, see the order page and note that everything below can also be dropped into the cloud-init / first-boot field. Want a domain to point at it later? 26 TLDs are available no-KYC.

Install WireGuard and enable IP forwarding

SSH in as root and install the tools. On Debian/Ubuntu:

apt update && apt install -y wireguard wireguard-tools nftables

# turn the box into a router
cat > /etc/sysctl.d/99-wireguard.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF
sysctl --system

Now generate the server keypair. umask 077 ensures the private key is never world-readable:

cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key
cat server_private.key   # you'll paste this into wg0.conf
cat server_public.key    # clients need this

Find your public network interface name (you'll need it for the NAT rule) and your public IP:

ip route get 1.1.1.1 | awk '{print $5; exit}'   # e.g. eth0 or ens3
curl -4 ifconfig.co                              # your public IPv4

Keep the private key on the server only. The no-KYC root password is stored AES-256 encrypted at rest, but your VPN keys are yours — never paste the server private key into a client.

Write the server config (wg0.conf)

Create /etc/wireguard/wg0.conf. This uses the 10.8.0.0/24 tunnel subnet and fd86:ea04:1115::/64 for IPv6. Replace SERVER_PRIVATE_KEY with the value you generated, and eth0 with your real interface from the previous step.

[Interface]
Address = 10.8.0.1/24, fd86:ea04:1115::1/64
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

# NAT: masquerade tunnel traffic out the public NIC
PostUp   = nft add table inet wg; \
           nft add chain inet wg postrouting '{ type nat hook postrouting priority 100 ; }'; \
           nft add rule inet wg postrouting oifname "eth0" masquerade
PostDown = nft delete table inet wg

# --- peers are appended below, one [Peer] per client ---

The PostUp rule is the entire NAT layer — it rewrites packets leaving the tunnel so they appear to come from the VPS's public IP, and the matching PostDown tears it down cleanly on stop. If you prefer ufw, run ufw route allow in on wg0 out on eth0 and add a masquerade block to /etc/ufw/before.rules instead, but the nftables one-liner above needs no extra files.

Open the WireGuard port and start the tunnel:

ufw allow 51820/udp        # if using ufw
systemctl enable --now wg-quick@wg0
wg show                    # confirm the interface is up

Generate keys and add a peer for each device

Every client (laptop, phone) gets its own keypair. Generate one on the server for convenience, or better, generate it on the device itself so the private key never leaves it. On the client:

umask 077
wg genkey | tee client_private.key | wg pubkey > client_public.key

Then append a [Peer] block to the server's wg0.conf using the client's public key. Each peer needs a unique tunnel IP:

[Peer]
# laptop
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32, fd86:ea04:1115::2/128

[Peer]
# phone
PublicKey = PHONE_PUBLIC_KEY
AllowedIPs = 10.8.0.3/32, fd86:ea04:1115::3/128

Apply the change without dropping existing tunnels:

wg syncconf wg0 <(wg-quick strip wg0)

Note the asymmetry: on the server, AllowedIPs is the narrow per-client tunnel IP (a routing/ACL entry). On the client, AllowedIPs is the wide 0.0.0.0/0 (what to send through the tunnel). Mixing these up is the single most common WireGuard mistake.

Client config, all platforms, and the kill-switch

On the client, create wg0.conf (or paste it into the app). Endpoint is your VPS public IP and the listen port. AllowedIPs = 0.0.0.0/0, ::/0 routes everything through the VPN:

[Interface]
PrivateKey = CLIENT_PRIVATE_KEY
Address = 10.8.0.2/32, fd86:ea04:1115::2/128
DNS = 9.9.9.9, 2620:fe::fe

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = YOUR_VPS_IP:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
  • Linux: save to /etc/wireguard/wg0.conf, then wg-quick up wg0. PersistentKeepalive = 25 keeps the tunnel alive behind NAT.
  • macOS / Windows: install the official WireGuard app, import the file or scan a QR code.
  • iOS / Android: install WireGuard from the app store. Generate a QR on the server with qrencode -t ansiutf8 < client.conf (apt install qrencode) and scan it — no typing.

Kill-switch

Because the client AllowedIPs is 0.0.0.0/0, ::/0, wg-quick installs a routing-based kill-switch automatically: it sets the tunnel as the default route and adds an fwmark rule that drops any packet not destined for the tunnel. If WireGuard stops, that default route disappears and traffic fails closed rather than leaking out your real interface. To make it strict on Linux, add PostUp/PreDown nftables rules that block all output except wg0 and the handshake to your endpoint. The mobile apps expose this as the "Block untunneled traffic / Exclude private IPs" toggle — turn it on.

Verify the exit IP is now your VPS: curl -4 ifconfig.co should return the server's address, not your ISP's. For a hardened, always-on box see the SSH hardening guide.

  1. Provision a no-KYC VPS

    Create an account with just email + password, top up the balance with Monero (XMR), and deploy an S1 VPS (from $5/mo) running Debian 13 or Ubuntu 24.04 in your chosen region. Build completes in about 47 seconds and you get root on a clean, dedicated IP.

  2. Install WireGuard

    apt update && apt install -y wireguard wireguard-tools nftables qrencode. The WireGuard module ships in the kernel, so there is nothing to compile.

  3. Enable IP forwarding

    Write net.ipv4.ip_forward = 1 and net.ipv6.conf.all.forwarding = 1 to /etc/sysctl.d/99-wireguard.conf and run sysctl --system. This turns the VPS into a router so it can forward your traffic to the internet.

  4. Generate the server keypair

    In /etc/wireguard run umask 077; wg genkey | tee server_private.key | wg pubkey > server_public.key. The private key stays on the server forever; the public key goes into each client config.

  5. Write wg0.conf with a NAT rule

    Create /etc/wireguard/wg0.conf with the [Interface] block (Address 10.8.0.1/24, ListenPort 51820, your private key) and a PostUp nftables masquerade rule on your public interface. Open UDP 51820 in the firewall.

  6. Add a peer per device

    Generate a keypair on each device, then append a [Peer] block to the server config with the client's public key and a unique tunnel IP (e.g. 10.8.0.2/32). Apply live with wg syncconf wg0 <(wg-quick strip wg0).

  7. Start the tunnel and connect clients

    Run systemctl enable --now wg-quick@wg0 on the server. On each client set AllowedIPs = 0.0.0.0/0, ::/0, Endpoint = YOUR_VPS_IP:51820, and bring it up — on mobile, scan a qrencode QR.

  8. Verify and enable the kill-switch

    Run curl -4 ifconfig.co on the client — it should return the VPS IP. Enable "Block untunneled traffic" in the app (or rely on wg-quick's default-route fail-closed) so nothing leaks if the tunnel drops.

FAQ

常见问题解答

Is running my own WireGuard VPN more private than a commercial VPN?
It depends on the threat model. A self-hosted exit gives you a dedicated IP nobody else shares and a zero-log policy you control instead of an unverifiable marketing claim. The tradeoff is that a single static IP doesn't blend into a crowd, so it's ideal for a private exit but not for anonymity-in-numbers — for that, layer Tor on top.
Will a $5 S1 VPS be fast enough for a VPN?
Yes. WireGuard runs in the kernel and is extremely light; an S1 (2 vCPU / 4 GB) will saturate the VPS's network link long before CPU becomes the bottleneck. NoKycVPS network runs up to 10 Gbps unmetered, so the practical cap is your own connection.
Can I pay for the VPS without any ID or KYC?
Yes. The entire credential is email + password — no ID, no phone, no documents, no email verification. You top up a balance with crypto (10 coins including Monero, which credits in about 30 seconds) and deploys debit that balance.
What's the difference between AllowedIPs on the server and on the client?
On the server, a peer's AllowedIPs is the narrow tunnel IP for that client (a routing/ACL rule). On the client, AllowedIPs is what you send through the tunnel — set it to 0.0.0.0/0, ::/0 to route all traffic. Swapping these is the most common WireGuard misconfiguration.
Does WireGuard have a built-in kill-switch?
Effectively yes. When the client AllowedIPs is 0.0.0.0/0, ::/0, wg-quick installs a default route plus an fwmark rule that drops any packet not bound for the tunnel, so traffic fails closed if WireGuard stops. The mobile apps expose this as a "Block untunneled traffic" toggle; on Linux you can add strict nftables output rules for belt-and-braces.

Deploy your offshore server.

选择地区。选择套餐。粘贴密钥。付款。接下来的47秒由我们负责。