← Start of tutorial

WIUNIX ACADEMY

Set up a routed WireGuard site-to-site VPN on Ubuntu and Debian

Page 5 of 8. Review the earlier steps and prerequisites before continuing.

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 26.10Reviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment24 editable values

Return routes belong on the actual LAN routers

Hosts keep their ordinary default router. In router A’s native persistent configuration add destination 10.20.20.0/24 via 10.10.10.2 on its LAN; B needs 10.10.10.0/24 via 10.20.20.2. Routers must already allow approved same-LAN next-hop forwarding. The next panels are TEMPORARY Linux-router tests, not commands for the VPN gateways. Before unattended use, save equivalent routes through the existing Netplan/networkd/NetworkManager/vendor configuration and verify persistence. If the VPN gateway IS the default LAN router, the extra ordinary-router route is unnecessary. Without router control, per-host routes via the local VPN gateway are a limited alternative. SNAT hides source identities and changes ACLs; it is not used to disguise a missing return route here.

12

LET’S BUILD

Temporary route on Linux router A

On router 10.10.10.1 only. Replace lan0 with its actual LAN interface. Stop if a route already owns this prefix; do not replace it.

Bash
ip -4 route show 10.20.20.0/24
sudo ip route add 10.20.20.0/24 via 10.10.10.2 dev lan0
ip route get 10.20.20.100
How do I know it worked?

Remote LAN goes through 10.10.10.2; save its equivalent in the router’s owning persistent configuration.

13

LET’S BUILD

Temporary route on Linux router B

On router 10.20.20.1 only, under the same no-overwrite and persistence conditions.

Bash
ip -4 route show 10.10.10.0/24
sudo ip route add 10.10.10.0/24 via 10.20.20.2 dev lan0
ip route get 10.10.10.100
How do I know it worked?

B’s router sends the remote prefix through 10.20.20.2.

14

LET’S BUILD

Generate traffic before judging the handshake

On gateway A, then inspect counters on B. Idle handshake age alone is not a fault; after traffic the timestamp must be recent/nonzero and RX/TX increase on both peers. Public keys must match the authenticated exchange.

Bash
ping -c 3 -W 2 10.255.255.2
sudo wg show wg0 latest-handshakes
sudo wg show wg0 transfer
ip route get 10.20.20.100
How do I know it worked?

Tunnel ping/handshake pass and the B LAN routes through wg0; LAN data still needs separate proof.

15

LET’S BUILD

Start a scratch receiver on LAN host B

On test host B in its own terminal. Port 8080 must be free and approved from the opposite test host in its existing firewall. Bind only the assigned LAN address and serve a new scratch directory. This is harmless HTTP test data, not a production service. Keep the terminal for Ctrl+C cleanup.

Bash
( set -eu
umask 077
demo_dir=$(mktemp -d)
printf 'received-at-site-B\n' > "$demo_dir/marker.txt"
python3 -m http.server 8080 --bind 10.20.20.100 --directory "$demo_dir"
)
How do I know it worked?

Receiver serves only its marker directory on the assigned LAN address.

16

LET’S BUILD

Read B receiver data from LAN host A

On test host 10.10.10.100, whose default router remains 10.10.10.1. Check the exact body and successful HTTP status, and confirm the receiver sees the original source. This traverses the actual routers and both LAN gateways; tunnel ping cannot substitute for it.

Bash
( set -eu
body=$(curl --fail --silent --show-error --noproxy '*' --connect-timeout 5 --max-time 10 http://10.20.20.100:8080/marker.txt)
test "$body" = received-at-site-B
printf 'B receiver body verified\n'
)
ping -c 3 -W 2 10.20.20.100
How do I know it worked?

Exact remote marker arrives and original source is visible at the receiver.

Explore all tutorials ↗