WireGuard Point to Site With a Site Gateway

Often when you connect a remote endpoint to a local site, you use NAT (Network Address Translation) to translate the remote endpoint’s IP address to the IP address of a host in the local site. But sometimes you need to maintain a unique IP address for each remote endpoint (usually for access control or audit logging). To do this with WireGuard, you need a WireGuard host at the local site that can act as a gateway between the remote WireGuard endpoints and the local site.

This article will describe how to accomplish this with a common WireGuard Point to Site Topology. In the example scenario, we’ll have an end-user workstation running WireGuard, which I’ll call “Endpoint A”, at some remote site; and another host running WireGuard at our local site, which I’ll call “Host β”, in “Site B”. Within Site B, we’ll have another endpoint, which I’ll call “Endpoint B”, running an HTTP server listening on port 80.

The Internet is between Endpoint A and Site B. Endpoint A is behind NAT (Network Address Translation) and a firewall that allows only established connections through. Site B is also behind NAT and a firewall, but its NAT + firewall allows port 51822 from the Internet to be forwarded on to Host β. We’ll use this port, 51822, for WireGuard on Host β. The firewall within Site B allows Host β to initiate new connections to Endpoint B on port 80.

The diagram below illustrates this scenario:

Wireguard point-to-site scenario

By connecting Endpoint A and Host β in a WireGuard VPN (Virtual Private Network), Endpoint A will be able to access the HTTP server running on Endpoint B as if Endpoint A were in the same LAN (Local Area Network) as Endpoint B. Endpoint B has an IP address of 192.168.200.22 within Site B, so a user using Endpoint A will be able to access the HTTP server on Endpoint B simply by navigating to http://192.168.200.22 in her web browser.

This is almost identical to the standard Point to Site Configuration — but in this case, instead of “masquerading” Endpoint A in Site B with Host β’s IP address (192.168.200.22), we’ll expose Endpoint A directly to Site B using Endpoint A’s own WireGuard IP address (10.0.0.1). This allows Endpoint B to use Endpoint A’s own address (10.0.0.1) for access control, as well as to include Endpoint A’s address in any log entries it records.

The only difference between this and the standard point-to-site configuration is, in fact, the routing configuration. So follow the first four sections of the Point to Site Configuration guide, and come back here when you hit the “Configure Routing” step.

Configure Routing

The two things we need to do to make routing work with Host β as a site gateway are:

  1. Turn on packet forwarding on Host β

  2. Update the routing tables at Site B

Since we’ll use wg-quick to bring the WireGuard tunnel up and down on Host β, the easiest way to make sure packet forwarding is on when the WireGuard tunnel is up is to have wg-quick do it for us. Update the /etc/wireguard/wg0.conf file on Host B to add the following Interface.PreUp setting:

# /etc/wireguard/wg0.conf

# local settings for Host β
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.0.0.2/32
ListenPort = 51822

# packet forwarding
PreUp = sysctl -w net.ipv4.ip_forward=1

# remote settings for Endpoint A
[Peer]
PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
AllowedIPs = 10.0.0.1/32

If you’re using IPv6 addresses for your WireGuard VPN, replace net.ipv4.ip_forward with net.ipv6.conf.all.forwarding.

Unfortunately, we can’t do the second thing — update the routing tables for Site B — via WireGuard. If we only had a few hosts in Site B (like say, just Endpoint B) that needed to be able to route to the WireGuard VPN, we could configure each of those hosts individually with a custom route. However, usually the simplest thing is to do is just update the configuration of the LAN router for the site to add a route to it for the WireGuard VPN.

If this router is a Linux box, run the ip route command on it to check what (IPv4) routes it is using currently (for IPv6, run ip -6 route). For our LAN router in Site B, the result might look something like this:

$ ip route
203.0.113.0/26 dev eth0 proto kernel scope link src 203.0.113.2
192.168.200.0/24 dev eth1 proto kernel scope link src 192.168.200.1
default via 203.0.113.1 dev eth0

The example above shows the gateway having an IP address of 203.0.113.2 on its eth0 (WAN, for Wide Area Network) network device, and 192.168.200.1 on its eth1 (LAN) device. The eth1 device is connected to the Site B subnet, 192.168.200.0/24.

Run the following command on the router to (temporarily) add a route to the WireGuard network through Host β on the eth1 (LAN) device:

$ sudo ip route add 10.0.0.0/24 via 192.168.200.2 dev eth1

Replace the subnet for Site B (10.0.0.0/24) with the actual subnet you’re using for the internal IP addresses on your WireGuard VPN; replace the IP address for Host β (192.168.200.2) with the actual Host β IP address you’re using; and replace the network device name (eth1) with the actual name of the device through which the router is connected to Site B.

Note that if you just want to route Endpoint A (and not any other WireGuard peers you may connect later to Host β), you could restrict the route to just Endpoint A, instead of your full WireGuard VPN subnet:

$ sudo ip route add 10.0.0.1/32 via 192.168.200.2 dev eth1

And note that adding a route this way just adds it temporarily, until the router is restarted or reconfigured — if you test out the WireGuard tunnel and everything works out, you’ll want to make the route change permanent via whatever mechanism you usually use to configure the router (like via networkd or netplan config files, or your own hand-built shell scripts, or some tool with a graphical user interface).

Start Up WireGuard

Now we’re ready to start up WireGuard and test out our WireGuard tunnel between Endpoint A and Host β. Go back to the standard Point to Site Configuration guide, and pick it back up at the “Start Up WireGuard” section.