WIUNIX ACADEMY
Set up a routed WireGuard site-to-site VPN on Ubuntu and Debian
Connect two non-overlapping LANs with dedicated WireGuard gateways. Verify peer identity, return routes, narrow firewall rules and real receiver data in both directions.
Make this guide yoursYOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
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
THE OUTCOME
What will you have at the end?
Two routed LANs with authenticated peers, explicit service policy, proven bidirectional receiver data and retained recovery inputs.
Supported operating systems and versions
OS paths are documentation-reviewed; isolated runtime evidence is distinct from complete distro installation and public-internet testing.
Before you begin
- Fresh gateways with preconfigured LAN/WAN, IPv4 management, independent consoles and no existing VPN/firewall manager.
- Non-overlapping LANs and control of persistent router routes and test-host policies.
- Reachable UDP endpoints and authenticated public peer identities.
Two sites and their actual routers
A uses LAN 10.10.10.0/24: ordinary router 10.10.10.1, VPN gateway 10.10.10.2, test host 10.10.10.100, WAN ens18 and LAN interface ens19. B uses 10.20.20.0/24: ordinary router 10.20.20.1, VPN gateway 10.20.20.2, test host 10.20.20.100, WAN ens18 and LAN interface ens19. Interfaces and addresses are already configured by their OS network manager. Tunnel wg0 uses A 10.255.255.1/30 and B 10.255.255.2/30. Public endpoints are A 198.51.100.10 and B 203.0.113.20, UDP 51820. Initial public/management values are documentation examples: configure actual reachable addresses and the real management source. LAN, tunnel and management ranges must not overlap.
Route selection, peer identity and firewall policy
The Linux route selects wg 0. WireGuard then selects a peer using the destination and AllowedIPs; on receive it checks the authenticated peer’s inner source address against that peer’s AllowedIPs. A lists B’s tunnel /32 and LAN, and B lists A’s. wg-quick automatically adds those routes. The firewall independently permits ICMP between the LANs and TCP 8080 only between the two test hosts, in either direction, plus established replies. There is no default route, DNS override, bridge, IPv6 VPN or masquerade. Real LAN source addresses remain visible. Encryption ends at the gateways; retain application authentication and TLS beyond them.
Fresh dedicated gateways and independent management
Use fresh systemd gateways with a tested out-of-band console and IPv4 SSH path. Do not apply this to production routers, Docker hosts, existing VPNs, UFW/firewalld hosts or a nonempty nftables ruleset. Other base chains can drop traffic despite an accept here. Keep the current SSH session open, then prove a SECOND session after enabling the filter. Management CIDR 192.0.2.0/24 and SSH 22 below are examples: replace with the actual source seen by each gateway and your real port. Upstream/cloud ACLs must separately permit the peer UDP exchange. This is a single IPv4 tunnel, not HA or uninterrupted-service proof.
What was actually exercised
Reviewed 2026-10-20. An isolated one-host lab used kernel 6.8 and distribution wireguard-tools 1.0.20210914: two gateways, two ordinary routers and two LAN hosts in six private network namespaces. Twenty-four checks covered real handshakes, exact bidirectional receiver data with original sources, blocked ports/sources, missing return-route and AllowedIPs failures, MTU, recovery from restored inputs and scoped reversal. The source backup/restore panels also ran with protected scratch-path substitutions. All lab children stopped. This is not a real internet/NAT, physical-site, full systemd boot, provider firewall, production SSH or all-OS installation test. Every selectable OS path remains documentation-reviewed.
LET’S BUILD
Inspect A and B without changing them
On both gateways as the existing sudo administrator, in Bash. Confirm selected OS, actual interfaces, addresses, routes, SSH source and listeners. Any existing key/config or forwarding workload is a stop condition. Missing directories and inactive/missing services are normal for a fresh host. If nft is absent, inspect its rules after installation.
. /etc/os-release
printf '%s %s\n' "$ID" "$VERSION_ID"
uname -r
ip -br address
ip -4 route show table all
ip rule show
printf 'SSH source/session: %s\n' "${SSH_CONNECTION:-console}"
sudo ss -lunpt
sudo sysctl net.ipv4.ip_forward
sudo find /etc/wireguard -maxdepth 1 -type f -print 2>/dev/null
systemctl is-active ufw firewalld nftables
Addresses and OS match; no existing VPN/firewall/routing workload is being replaced.
LET’S BUILD
Install from this OS release’s repositories
On both fresh gateways. APT verifies signed distro metadata and hashes. Reviewed stock kernels provide WireGuard: no foreign-release repository, DKMS workaround or downloaded installer. A restricted container can lack NET_ADMIN; use a supported VM instead of changing production kernel settings. Test hosts need curl and python3 from their own distribution.
sudo apt-get update
sudo apt-get install wireguard-tools nftables iproute2 iputils-ping curl python3 nano
wg --version
dpkg-query -W wireguard-tools nftables
sudo nft list ruleset
Tools are present and the ruleset is EMPTY. If rules or another firewall manager exist, STOP and integrate through their owner.