Your Own Multi-Hop VPN: Chain Two WireGuard Servers

Difficulty: Advanced 12 min read Updated: 22.07.2026 11
Your Own Multi-Hop VPN: Chain Two WireGuard Servers
Route your traffic through two servers you control by chaining two WireGuard VPS into a private multi-hop VPN - the most private double-hop setup there is.

A multi-hop VPN routes your traffic through two servers in two different countries, so no single machine ever knows both who you are and what you are doing. Commercial VPNs offer this as "Double VPN" or "Secure Core", but the most private version is one you build yourself from two servers only you control. This guide chains two WireGuard servers - an entry server you connect to and an exit server your traffic leaves from - so your real IP is hidden behind two hops that nobody else can log.

Before you start: this is an advanced guide. If you have not set up a single WireGuard server yet, follow our WireGuard on a VPS guide first - this one assumes you are comfortable with that process. You will need two VPS, ideally from different providers in different countries, both running a fresh Ubuntu or Debian, with root access.

How the chain works

Your device connects only to the entry server. The entry server does not send your traffic straight to the internet - instead it forwards everything through a second WireGuard tunnel to the exit server, which then reaches the internet. So the path is: you → entry → exit → internet. The entry server sees your real IP but never your destination; the exit server sees your destination but only ever sees the entry server. Websites see the exit server's IP. We will give the exit server the address range 10.8.0.0/24 and the entry server 10.7.0.0/24 for your devices.

Step 1: Set up the exit server

The exit server is just a normal WireGuard server. On the exit VPS, install WireGuard and generate its keys:

apt update && apt install -y wireguard
wg genkey | tee /etc/wireguard/exit.key | wg pubkey > /etc/wireguard/exit.pub
cat /etc/wireguard/exit.key   # this is EXIT_PRIVATE_KEY
cat /etc/wireguard/exit.pub   # this is EXIT_PUBLIC_KEY

Find your public network interface (usually eth0) with ip route show default. Then create /etc/wireguard/wg0.conf on the exit server:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = EXIT_PRIVATE_KEY
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# The entry server (we add its key in Step 4)
PublicKey = ENTRY_LINK_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32

Replace eth0 if your interface differs. Leave ENTRY_LINK_PUBLIC_KEY as a placeholder for now - we generate it in Step 4.

Step 2: Turn on forwarding and start the exit

Enable IP forwarding permanently, then start WireGuard on the exit server:

echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-wg.conf
sysctl -p /etc/sysctl.d/99-wg.conf
ufw allow 51820/udp
systemctl enable --now wg-quick@wg0

Note the exit server's public IP - we will call it EXIT_IP.

Step 3: Set up the entry server (your side)

On the entry VPS, install WireGuard and generate two key pairs - one for the tunnel that faces your devices (wg0) and one for the link to the exit (wg1):

apt update && apt install -y wireguard
wg genkey | tee /etc/wireguard/entry0.key | wg pubkey > /etc/wireguard/entry0.pub   # faces your devices
wg genkey | tee /etc/wireguard/entry1.key | wg pubkey > /etc/wireguard/entry1.pub   # link to exit

The public key in entry1.pub is the ENTRY_LINK_PUBLIC_KEY you left as a placeholder on the exit server in Step 1 - go back and paste it into the exit's wg0.conf now, then run systemctl restart wg-quick@wg0 on the exit server.

Step 4: Create the entry-to-exit link (wg1)

On the entry server, create /etc/wireguard/wg1.conf. This makes the entry server a client of the exit server:

[Interface]
Address = 10.8.0.2/24
PrivateKey = ENTRY_LINK_PRIVATE_KEY
# Do NOT route the whole server through the exit - that would cut your own SSH.
# Send only your client subnet (10.7.0.0/24) through the exit, via a separate table.
Table = off
PostUp = ip rule add from 10.7.0.0/24 table 120; ip route add default dev wg1 table 120
PostDown = ip rule del from 10.7.0.0/24 table 120; ip route del default dev wg1 table 120

[Peer]
# The exit server
PublicKey = EXIT_PUBLIC_KEY
Endpoint = EXIT_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

ENTRY_LINK_PRIVATE_KEY is the contents of entry1.key. This is the most important step to get right. A plain AllowedIPs = 0.0.0.0/0 would make WireGuard route the entry server's own traffic - including your SSH session - through the exit, which breaks your access to the server. Table = off stops that, and the policy-routing rules send only your client subnet through the exit, leaving the server itself reachable as normal.

Step 5: Create the entry tunnel for your devices (wg0)

Still on the entry server, create /etc/wireguard/wg0.conf. This is the tunnel your phone or laptop connects to, and the routing rules push that traffic into wg1:

[Interface]
Address = 10.7.0.1/24
ListenPort = 51820
PrivateKey = ENTRY_DEVICE_PRIVATE_KEY
PostUp = iptables -A FORWARD -i wg0 -o wg1 -j ACCEPT; iptables -A FORWARD -i wg1 -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg1 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -o wg1 -j ACCEPT; iptables -D FORWARD -i wg1 -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o wg1 -j MASQUERADE

[Peer]
# Your device (we add its key in Step 6)
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.7.0.2/32

ENTRY_DEVICE_PRIVATE_KEY is the contents of entry0.key. The masquerade on wg1 hides your device behind the entry server, so the exit only ever sees the entry.

Step 6: Create your device config and connect

Generate a key pair for your device (on your computer, or on the entry server), then build the client config. Put the device's public key into the entry's wg0.conf where it says CLIENT_PUBLIC_KEY. Your device config looks like this:

[Interface]
PrivateKey = CLIENT_PRIVATE_KEY
Address = 10.7.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = ENTRY_DEVICE_PUBLIC_KEY
Endpoint = ENTRY_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Here ENTRY_DEVICE_PUBLIC_KEY is from entry0.pub, and ENTRY_IP is the entry server's public IP - the only server your device ever talks to.

Step 7: Start the entry and verify the chain

On the entry server, enable forwarding and start both tunnels in order (the link first, then the device tunnel):

echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-wg.conf
sysctl -p /etc/sysctl.d/99-wg.conf
ufw allow 51820/udp
systemctl enable --now wg-quick@wg1
systemctl enable --now wg-quick@wg0

Now import the client config into the WireGuard app on your device and connect. To confirm the chain works, check your IP - it should show the exit server's country, not the entry's:

curl https://api.ipify.org

If that returns the exit server's IP, your traffic is hopping through both servers. Run a leak test on our network tools page to be sure there are no DNS or WebRTC leaks.

Common mistakes: if you have no internet after connecting, check that IP forwarding is on (sysctl net.ipv4.ip_forward should return 1) on both servers, that the exit server has your entry key in its [Peer] block, and that both firewalls allow UDP 51820. If the IP shows the entry country instead of the exit, the MASQUERADE -o wg1 rule on the entry did not load - restart wg0 on the entry server.

Is it worth it?

A self-hosted multi-hop is the most private setup there is: two servers you own, in two countries, with no provider in the middle keeping logs. The trade-offs are speed (two hops add latency) and cost (two VPS instead of one). For everyday browsing a single server is plenty; build the chain when your threat model genuinely calls for it. And remember: a multi-hop protects your privacy, it does not change the law of wherever you live.

Tags: multihop double vpn wireguard self-hosted advanced