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:
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.
The two things we need to do to make routing work with Host β as a site gateway are:
Turn on packet forwarding on Host β
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
# /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
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,
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
netplan config files, or your own hand-built shell scripts, or some tool with a graphical user interface).
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.