WireGuard between two sites#
You will end up with two routers joined by a WireGuard tunnel, each reaching the other's LAN. The configuration is the same shape as a road-warrior tunnel; the differences are that both ends have a fixed endpoint, and both ends carry routes.
Before you start#
- The operator role and a licence on both routers.
- The WireGuard feature module installed on both.
- A key pair per router:
generate pki wireguard key-pair. - Non-overlapping LAN subnets. Two sites both on
192.168.1.0/24cannot route to each other, and nothing in this guide fixes that. - At least one side reachable at a stable address. If both are behind changing addresses, dynamic DNS on one side is the minimum.
Worked example throughout:
| Site A | Site B | |
|---|---|---|
| LAN | 192.0.2.0/24 | 198.51.100.0/24 |
| Public address | 203.0.113.10 | 203.0.113.20 |
| Tunnel address | 10.10.0.1/30 | 10.10.0.2/30 |
Step 1 — The tunnel on each side#
Site A:
set interfaces wireguard wg0 port 51820
set interfaces wireguard wg0 address 10.10.0.1/30
set interfaces wireguard wg0 private-key <site A private key>
set interfaces wireguard wg0 description 'to site B'Site B:
set interfaces wireguard wg0 port 51820
set interfaces wireguard wg0 address 10.10.0.2/30
set interfaces wireguard wg0 private-key <site B private key>
set interfaces wireguard wg0 description 'to site A'A /30 is enough for a point-to-point link and makes it obvious that this tunnel is for
two machines.
Step 2 — The peer on each side#
This is where a site-to-site peer differs from a laptop: it has an endpoint and a keepalive, and its allowed IPs include the far LAN.
Site A:
set interfaces wireguard wg0 peer siteB public-key <site B public key>
set interfaces wireguard wg0 peer siteB allowed-ips 10.10.0.2/32
set interfaces wireguard wg0 peer siteB allowed-ips 198.51.100.0/24
set interfaces wireguard wg0 peer siteB address 203.0.113.20
set interfaces wireguard wg0 peer siteB port 51820
set interfaces wireguard wg0 peer siteB persistent-keepalive 25Site B: the mirror image, with A's key, A's LAN and A's address.
allowed-ips on a peer is both a filter and a route hint: traffic for those prefixes goes
into the tunnel, and traffic arriving from that peer is accepted only if its source is in
that list. Getting it wrong produces a tunnel that handshakes and drops traffic silently.
persistent-keepalive 25 keeps a NAT binding alive on a side that is behind NAT. It costs
almost nothing and saves the "works for a minute, then stops" problem.
Step 3 — Routes#
If the far LAN is in the peer's allowed-ips, WireGuard installs a route for it. On a
design where you want the route explicit — and you usually do, because it shows up on
the Static routes page — add it:
set protocols static route 198.51.100.0/24 next-hop 10.10.0.2Step 4 — The firewall, on both sides#
The listener:
set firewall ipv4 input filter rule 100 action accept
set firewall ipv4 input filter rule 100 description 'wireguard from the far site'
set firewall ipv4 input filter rule 100 protocol udp
set firewall ipv4 input filter rule 100 destination port 51820
set firewall ipv4 input filter rule 100 source address 203.0.113.20Scoping it to the far site's address is worth doing when that address is stable.
And the traffic, in both directions:
set firewall ipv4 forward filter rule 40 action accept
set firewall ipv4 forward filter rule 40 description 'site B to here'
set firewall ipv4 forward filter rule 40 inbound-interface name wg0
set firewall ipv4 forward filter rule 41 action accept
set firewall ipv4 forward filter rule 41 description 'here to site B'
set firewall ipv4 forward filter rule 41 outbound-interface name wg0Step 5 — Do not masquerade#
A common mistake carried over from a road-warrior setup. If the source NAT rule on the uplink matches everything leaving the router, traffic destined for the tunnel can be translated before it gets there, and the far side sees your public address instead of your LAN. Check that the masquerade rule names the uplink interface as its outbound interface — which is what the Uplinks page writes — rather than matching on source alone. Masquerade behind each uplink.
Check it worked#
# on either router
sudo wg show
show interfaces wireguard wg0
ping -c 3 10.10.0.2
# from a host on site A's LAN
ping -c 3 198.51.100.1
traceroute 198.51.100.1wg show reports the last handshake and the bytes each way. A handshake with no bytes is
an allowed-IPs or firewall problem; no handshake is a key, endpoint or port problem.
The WireGuard page shows configuration, not handshakes. Tunnels, peers and their
allowed IPs are there; live handshake times and transfer counters are not, because they
would need wg show exposed by the agent, which it does not do.
Undoing it#
delete interfaces wireguard wg0
delete protocols static route 198.51.100.0/24
delete firewall ipv4 input filter rule 100
delete firewall ipv4 forward filter rule 40
delete firewall ipv4 forward filter rule 41on both sides. Deleting one side leaves the other retrying against a peer that is not there, which is harmless and noisy.
See also#
- A WireGuard tunnel for a laptop
- An IPsec tunnel to a third-party device — when the far end is not yours
- GRE, IPIP, SIT and VXLAN interfaces — unencrypted tunnels, and when they are the right answer
- WireGuard
Checked against ui/src/pages/WireGuard.tsx ·
ui/src/pages/Wan.tsx ·
ui/src/pages/Firewall.tsx