← Start of tutorial

WIUNIX ACADEMY

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

Page 6 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.

Debian 13Reviewed 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
17

LET’S BUILD

Start a scratch receiver on LAN host A

On test host A 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-A\n' > "$demo_dir/marker.txt"
python3 -m http.server 8080 --bind 10.10.10.100 --directory "$demo_dir"
)
How do I know it worked?

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

18

LET’S BUILD

Read A receiver data from LAN host B

On test host 10.20.20.100, whose default router remains 10.20.20.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.10.10.100:8080/marker.txt)
test "$body" = received-at-site-A
printf 'A receiver body verified\n'
)
ping -c 3 -W 2 10.10.10.100
How do I know it worked?

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

Diagnose the packet path

Use the focused panels below. Never post private configs or full wg dumps. Recent handshake without LAN data points to forwarding, source validation, return routes or host policy. No handshake starts with public identity, endpoint and UDP policy; UDP scanning alone does not prove an authenticated peer.

No handshake: peer and endpoint

On A/B. Replace the route query with the opposite REAL endpoint. Redact network metadata before sharing journal excerpts.

Bash
sudo wg show wg0 public-key
sudo wg show wg0 endpoints
sudo wg show wg0 latest-handshakes
sudo ss -lunp
ip route get 203.0.113.20
sudo journalctl -u wg-quick@wg0.service -n 40 --no-pager
sudo nft list table inet academy_wg

Handshake passes; LAN data fails

On A; use symmetric addresses on B. Check actual routers’ return routes and hosts’ firewalls too. Strict reverse-path filtering can reject a separately designed asymmetric route: fix routing first, do not disable validation globally.

Bash
ip route get 10.20.20.100 from 10.10.10.100 iif ens19
sudo sysctl net.ipv4.ip_forward net.ipv4.conf.all.rp_filter net.ipv4.conf.ens19.rp_filter net.ipv4.conf.wg0.rp_filter
sudo wg show wg0 allowed-ips
sudo wg show wg0 transfer
sudo nft list chain inet academy_wg forward

Small packets work; large packets stall

On LAN host A. IPv4 payload plus 28 is inner packet size. One failed ping can also mean ICMP filtering; allow fragmentation-needed across the underlay and check representative TCP transfers before diagnosing MTU.

Bash
ping -c 3 -W 2 -M do -s 1200 10.20.20.100
ping -c 3 -W 2 -M do -s 1392 10.20.20.100
Explore all tutorials ↗