WireGuard Site to Site Configuration
This article will cover how to set up two WireGuard peers in a Site to Site topology. This is the configuration you’d use when you want to connect a variety of computers at one site through a single WireGuard tunnel to a variety of computers at another site; like to connect the LAN (Local Area Network) of one office location to another, or to connect your office network to a bunch of servers you have set up in a cloud network.
In the specific scenario I’ll cover for this article, we’ll have “Host α” running WireGuard in one LAN, “Site A”, connected across the Internet to “Host β” running WireGuard in another LAN, “Site B”. Host α will be configured as the gateway from Site A to Site B, and Host β as the gateway from Site B to Site A. “Endpoint A” is an end-user workstation in Site A that will be able to connect through our WireGuard tunnel to an HTTP server on “Endpoint B” in Site B.
The diagram below illustrates this scenario:
In order to accomplish this, Host α needs to be able to connect through Site B’s firewall to UDP port 51822 on Host β, and Host β needs to be able to connect through Site A’s firewall to UDP port 51821 on Host α. From the perspective of Host β and the Internet, Host α’s IP address is 198.51.100.1
, but from the perspective of Site A, Host α’s IP address is 192.168.1.1
, and from the perspective of the WireGuard tunnel between Host α and Host β, Host α’s IP address will be 10.0.0.1
.
Similarly, from the perspective of Host α and the Internet, Host β’s IP address is 203.0.113.2
, and from the perspective of Site B, Host β’s IP address is 192.168.200.2
, and from the perspective of the WireGuard tunnel between Host α and Host β, Host β’s IP address will be 10.0.0.2
.
Endpoint A’s IP address will be 192.168.1.11
, and Endpoint B’s IP address will be 192.168.200.22
. With the WireGuard tunnel up and running, a user on 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 article will walk through how to install and configure WireGuard on Host α and Host β, as well as how to configure Host α and Host β to allow them to route packets between Site A and Site B. These are the steps we’ll follow:
Install WireGuard
Install WireGuard on both Host α and Host β by following the installation instructions for the appropriate platform on the WireGuard Installation page. You can verify that you’ve installed WireGuard successfully by running wg help
on both hosts.
Generate Keys
Next, generate two WireGuard keys, one for Host α, and one for Host β. A WireGuard key (also known as a “key pair”) is composed of two parts, the “private key” (also known as the “secret key”), and the “public key”. The magic of this kind of crypto (known as “public-key cryptography”) is that it’s trivial to compute the public key if you know the private key, but practically impossible to compute the private key if all you know is the public key.
While you don’t have to generate the keys on the hosts, generating a host’s key on the host itself often is the best way to keep its private key secure — that way the private key never leaves the host. If you generate your keys outside of the host, be very careful with the private keys, as WireGuard’s security depends entirely on keeping the private keys a secret.
Run the following commands to generate a new key pair for Host A:
$ wg genkey > host-a.key
$ wg pubkey < host-a.key > host-a.pub
And similar commands to generate a new key pair for Host β:
$ wg genkey > host-b.key
$ wg pubkey < host-b.key > host-b.pub
This will generate four files: host-a.key
, host-a.pub
, host-b.key
, and host-b.pub
. The *.key
files contain the private keys, and the *.pub
files contain the public keys. The content of each will be 44 characters of Base64-encoded text:
$ cat host-a.key
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
$ cat host-a.pub
/TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
$ cat host-b.key
ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
$ cat host-b.pub
fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
You don’t actually need to keep these files around — the content of each will be used in the WireGuard configuration files we build for Host α and Host β in the next sections. The private key for a host goes in the host’s own configuration file; and its public key goes in the configuration file of every other host you want to connect it to. Each end of a connection must be pre-configured with the other end’s public key in order for WireGuard to establish the connection.
Configure WireGuard
Now let’s configure WireGuard. On Host α, create a new file at /etc/wireguard/wg0.conf
with the following content:
# /etc/wireguard/wg0.conf # local settings for Host α [Interface] PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= Address = 10.0.0.1/32 ListenPort = 51821 # remote settings for Host β [Peer] PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds= Endpoint = 203.0.113.2:51822 AllowedIPs = 192.168.200.0/24
And on Host β, create a new file at the same location with the following content:
# /etc/wireguard/wg0.conf # local settings for Host β [Interface] PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA= Address = 10.0.0.2/32 ListenPort = 51822 # remote settings for Host α [Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= Endpoint = 198.51.100.1:51821 AllowedIPs = 192.168.1.0/24
Set each file’s owner to root
, and its permissions to 600
(owner can read+write; everyone else is denied access — the file contains the endpoint’s private key, which must be kept secret).
With a Site to Site topology, the configuration of the two WireGuard hosts usually will be perfectly symmetrical, with the [Interface]
section for each host describing the host itself, and the [Peer]
section describing the other host. Let’s go through each configuration setting:
- Interface.PrivateKey
-
This is the host’s own private key — replace this value with the actual private key you generated for the host. This value is secret, and this is the only place where it should live.
- Interface.Address
-
This is the host’s IP address inside the WireGuard VPN we’re building — replace this value with a suitable value for your network. You can use any address you want for this, but the address should be within the “Private-Use” IPv4 or “Unique-Local” IPv6 address space (like
10.0.0.0/8
— see RFC 6890 for all available address blocks), and should not collide with any other private subnets to which the host itself or any of its peers can connect.This setting isn’t used by WireGuard directly — it’s only used by the
wg-quick
helper service when it sets up a virtual network interface for WireGuard. In order for network packets to be routed correctly to and from this host when they’re outside of the WireGuard tunnel, they need to use the IP address you set here.Also, with a Site to Site topology, this setting isn’t all that important — typically you want route packets through the host (and on to other endpoints in the site), not to the host itself. So you just need to make sure you pick an IP address that isn’t going to collide with any other IP addresses the host can route to.
While you can configure multiple IP addresses for this setting, unless you have a special use-case, you should just use a single IP address (in the form of a
/32
block with an IPv4 address, or a/64
block with an IPv6 address). - Interface.ListenPort
-
This is the host’s WireGuard port. The host must be able to receive UDP traffic for new connections on this port from the Internet (or wherever the traffic of the other WireGuard peers with which it will communicate comes from).
With a Site to Site topology, this setting in Host α’s configuration file should match the port in the
Peer.Endpoint
setting of Host β’s configuration file, and vice versa. - Peer.PublicKey
-
This is the other host’s public key — replace this value with the actual public key you generated for the other host. On Host α, this should be Host β’s public key; and on Host β, this should be Host α’s public key.
- Peer.Endpoint
-
This is the other host’s publicly-facing IP address (and port) — the IP address and port this host will use to connect over the Internet to the other host to set up the WireGuard tunnel. Replace this value with the actual IP address that you would normally use to connect to the other host (and suffix it with the actual WireGuard port you’ll use for the other host).
In our example, Host β’s public IP address is
203.0.113.2
(and WireGuard is listening on port51822
of Host β), so that’s the IP address (and port) we put in thePeer.Endpoint
setting on Host α. And Host α’s public IP address is198.51.100.1
(with WireGuard listening on port51821
), so that’s the address (and port) we put in thePeer.Endpoint
setting on Host β.Host α must be able to accept new UDP connections from the internet at this address and port (
198.51.100.1:51821
), and Host β similarly must be able to accept new UDP connections from the Internet at its address and port (203.0.113.2:51822
). - Peer.AllowedIPs
-
This is the other site’s subnet block — replace this value with the actual block of IP addresses the other site uses. If the other host can route to multiple subnets within the other site, you can specify each block of IP addresses separated by commas (like
192.168.200.0/24, 192.168.202.64/26, 192.0.2.48/28
) for this setting, or you can just specify this setting multiple times, one for each CIDR (Classless Inter-Domain Routing) block.In our example, Site B’s subnet block is
192.168.200.0/24
, so that’s the block we put in thePeer.AllowedIPs
setting on Host α. And Site A’s subnet block is192.168.1.0/24
, so that’s the block we put in thePeer.AllowedIPs
setting on Host β.
Tip
|
If you want to allow one (or both) of the WireGuard hosts itself to be able to access the other site, you need to add the WireGuard address of the host to the other site’s For example, if you want to run
You may then also have to add a route for this address to Site B, as described in the next section. |
Configure Routing
If both WireGuard hosts are already set up as the Internet gateway for their site (or the gateway in their site to a subnet that includes the other site’s LAN), you don’t need to do anything extra for WireGuard; just skip on to the next section.
Otherwise, we need to do two things:
-
Turn on IP forwarding on the WireGuard hosts
-
Update the routing tables for each site
Since we’ll use wg-quick
to bring the WireGuard tunnel up and down on Host α and Host β, the easiest way to make sure IP forwarding is on when the WireGuard tunnel is to have wg-quick
do it for us when it brings the WireGuard tunnel up. Update the /etc/wireguard/wg0.conf
file on Host α to add the following Interface.PreUp
setting:
# /etc/wireguard/wg0.conf # local settings for Host α [Interface] PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= Address = 10.0.0.1/32 ListenPort = 51821 # IP forwarding PreUp = sysctl -w net.ipv4.ip_forward=1 # remote settings for Host β [Peer] PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds= Endpoint = 203.0.113.2:51822 AllowedIPs = 192.168.200.0/24
And add the exact same setting to the /etc/wireguard/wg0.conf
on Host β:
# /etc/wireguard/wg0.conf # local settings for Host β [Interface] PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA= Address = 10.0.0.2/32 ListenPort = 51822 # IP forwarding PreUp = sysctl -w net.ipv4.ip_forward=1 # remote settings for Host α [Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= Endpoint = 198.51.100.1:51821 AllowedIPs = 192.168.1.0/24
If you’re using IPv6 addresses for your WireGuard VPN, use this Interface.PreUp
setting instead (on both hosts):
PreUp = sysctl -w net.ipv6.conf.all.forwarding=1
For the second thing, updating each site’s routing tables, unfortunately you can’t do via WireGuard config. You could configure each endpoint in both sites individually to route the traffic it generates destined for the other site through the WireGuard host in its own site — but the easiest thing to do is simply update the configuration of an existing gateway in each site to do that routing.
So for Site A, you want to update the gateway for the subnet that subsumes Site B’s subnet (192.168.200.0/24
), which usually would be the default gateway for Site A (like if Site A is a small office, it’s probably the Internet router for the office). You want to add a route to this gateway to make it route Site B’s subnet (192.168.200.0/24
) via Host α (192.168.1.1
) on the Site A (LAN) side of the gateway.
If this gateway is a Linux box, run the ip route
command on the gateway to check what (IPv4) routes it currently is using (for IPv6, run ip -6 route
). On Site A, the result might look something like this:
$ ip route
192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.100
192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.128
default via 192.0.2.1 dev eth0
The example above shows the gateway having an IP address of 192.0.2.100
on its eth0
network device, and 192.168.1.128
on its eth1
device. The eth1
device is connected to the Site A subnet, 192.168.1.0/24
.
So run the following command on the gateway to (temporarily) add a route to Site B through Host α on the eth1
device:
ip route add 192.168.200.0/24 via 192.168.1.1 dev eth1
Replace the subnet for Site B (192.168.200.0/24
) with the actual Site B subnet you’re using, the IP address for Host α (192.168.1.1
) with the actual Host α IP address you’re using, and the network device name (eth1
) with the actual name of the device through which the gateway is connected to Site A.
Note that adding a route this way just adds it temporarily, until the gateway 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 regularly use to configure the gateway (like via networkd
or netplan
config files, or your own hand-built shell scripts, or some tool with a graphical user interface).
Similarly, check the routes used on Site B’s default gateway with ip route
, and then run a command on it like the following on it to add a route to Site A through Host β:
ip route add 192.168.1.0/24 via 192.168.200.2 dev eth1
Start Up WireGuard
On both Host α and Host β, start the wg-quick
service. On Linux with systemd, run the following commands:
$ sudo systemctl enable wg-quick@wg0.service
$ sudo systemctl start wg-quick@wg0.service
On systems without systemd, run this command instead:
$ sudo wg-quick up /etc/wireguard/wg0.conf
Either way, starting up the wg-quick
service will set up a WireGuard network interface named wg0
on the host, and configure some routing rules to route packets destined for any IP address listed in the Peer.AllowedIPs
setting(s) of the /etc/wireguard/wg0.conf
file to go out the wg0
interface.
Note that the name wg0
is just the standard convention for your first WireGuard interface. You can create as many WireGuard interfaces as you like, and name them however you like. For example, you could create another configuration file named /etc/wireguard/mytunnel.conf
, and start it up with the command wg-quick up /etc/wireguard/mytunnel.conf
; this would create a new WireGuard interface named mytunnel
.
But for now, if you ran wg-quick up
directly, you’ll see output like the following:
$ sudo wg-quick up /etc/wireguard/wg0.conf
[#] sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.1/32 dev wg0
[#] ip link set mtu 8921 up dev wg0
[#] ip -4 route add 10.0.0.2/32 dev wg0
This output shows the routing rules that wg-quick
set up for you automatically.
If you ran systemctl start
instead, you can see the same output by running the journalctl
tool, like so:
$ journalctl -u wg-quick@wg0.service
systemd[1]: Starting WireGuard via wg-quick(8) for wg0...
wg-quick[271288]: [#] sysctl -w net.ipv4.ip_forward=1
wg-quick[271288]: net.ipv4.ip_forward = 1
wg-quick[271288]: [#] ip link add wg0 type wireguard
wg-quick[271288]: [#] wg setconf wg0 /dev/fd/63
wg-quick[271288]: [#] ip -4 route add 10.0.0.1/32 dev wg0
wg-quick[271288]: [#] ip link set mtu 8921 up dev wg0
wg-quick[271288]: [#] ip -4 address add 10.0.0.2/32 dev wg0
systemd[1]: Started WireGuard via wg-quick(8) for wg0.
Test Out the Tunnel
On Endpoint B, start up a webserver on port 80 (or any other port, like 8080). If you don’t have a webserver handy, a dead-simple substitute is to use the http.server
module of Python 3, like the following, running as root to listen on port 80:
$ sudo python3 -m http.server 80
Or run it as a regular user to listen on any port above 1023 (like port 8080):
$ python3 -m http.server 8080
The http.server
module will serve the directory listing of and files in your current directory. A somewhat safer version of this is to create an empty directory in your current directory, and serve that instead:
$ mkdir dummydir && cd dummydir
$ python3 -m http.server 8080
On Endpoint A, use curl
(or a regular webrowser) to request a page from the webserver running on Endpoint B port 80:
$ curl 192.168.200.22
Or if the webserver is running on port 8080 (or some other port), specify that port explicitly:
$ curl 192.168.200.22:8080
If you see any HTML output from this, your WireGuard tunnel works!
Basic Troubleshooting
If curl
hangs, or you see an error like like Connection refused
or No route to host
, you may have neglected to turn on IP forwarding on one of your WireGuard hosts. Run this command on Host α and Host β to double check:
$ sudo sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
Or, if you’re using IPv6 addresses, run the IPv6 variant:
$ sudo sysctl net.ipv6.conf.all.forwarding
net.ipv6.conf.all.forwarding = 0
If the result is 0
, you need to turn on IP forwarding (see the Configure Routing section above). If the result is 1
, IP forwarding is on.
The next thing to do is to try to use traceroute
or tracepath
to see how ICMP packets are being routed between Endpoint A and Endpoint B. If we run tracepath 192.168.200.22
(Endpoint B’s IP address) from Endpoint A, we might see a result like this:
$ tracepath 192.168.200.22
1?: [LOCALHOST] pmtu 1500
1: 192.168.1.1 0.411ms
2: no reply
3: no reply
4: no reply
...
The above result indicates that our ICMP packets from Endpoint A only got as far as Host α. What we should see is something like this:
$ tracepath 192.168.200.22
1?: [LOCALHOST] pmtu 1500
1: 192.168.1.1 0.411ms
2: 10.0.0.2 3.832ms pmtu 1420
3: 192.168.200.22 0.390ms reached
Resume: pmtu 1420 hops 3 back 3
The above indicates our ICMP packets made it all the way to Endpoint B and back.
If the packets never even make it to Host α, that probably means that you need to work on the routing rules for Site A (see the Configure Routing section above). If the packets stop at Host α, probably either the tunnel from Host α to Host β wasn’t set up successfully, or Host β’s own firewall rules are blocking packets. If the packets stop at Host β, probably either the routing rules in Site B, or a firewall between Host β and Endpoint B, is to blame.
If you’re using iptables
on your WireGuard hosts, you can double-check the hosts’ active firewall rules by running sudo iptables-save
(see the Extra: Configure Firewall_ section below for some iptables
rules suggestions). If you’re using nftables
, you can get a similar list via sudo nft list ruleset
. If you see nothing from either command, you have no firewall set up; if you see an error, you probably don’t have iptables
or nftables
installed.
If everything on Host α and Host β seem to be right, but packets still seem to be stopping at Host α, you likely have some other firewall rules or network configuration blocking the WireGuard tunnel itself from being set up. Try running sudo wg
on both Host α and Host β, to see if the WireGuard interface on both is up and configured as you expect.
On Host β, you’ll probably see output like this:
$ sudo wg
interface: wg0
public key: fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
private key: (hidden)
listening port: 51822
peer: /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
allowed ips: 192.168.1.0/24
If Host α had successfully connected to Host β, Host β’s display would include a “latest handshake” field under the peer line, as well as a “transfer” field indicating some data had been received. The above output indicates that Host α has not successfully connected yet.
On Host α, you’ll probably see output like this:
$ sudo wg
interface: wg0
public key: /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
private key: (hidden)
listening port: 51821
peer: fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
endpoint: 203.0.113.2:51822
allowed ips: 192.168.200.0/24
transfer: 0 B received, 123 B sent
If the “transfer” field indicates some data has been sent to Host β, but none has been received (as it does above), it likely means packets are being blocked or misdirected somewhere between Host α and Host β before the hosts are able to set up the WireGuard tunnel. If this is the case for you, you need to fiddle with your firewalls or other network configuration until they allow Host α to send UDP packets to Host β via the IP address and port configured in Host α’s Peer.Endpoint
setting (in this example, it’s 203.0.113.2:51822
), and vice versa.
Extra: Configure Firewall
If you already have some basic firewall rules for forwarded traffic set up on your WireGuard hosts, you don’t need to do anything else to your WireGuard configuration. If you don’t already have some basic rules in place, however, here are a few simple iptables
rules that you can use to reject unexpected WireGuard traffic from accessing local sockets on the WireGuard hosts themselves, and to reject any WireGuard traffic from being forwarded to unexpected destinations within your sites.
I’ll go over these rules using Site B as an example, where for now we want to block any WireGuard traffic except to and from port 80 on Endpoint B. You can apply similar rules to Site A (adding additional --state NEW
rules for each service in the site that you want to allow the other site to be able to initiate access to).
First, bring down the WireGuard interface on Host β with wg-quick
or systemctl
:
$ sudo wg-quick down /etc/wireguard/wg0.conf
$ # or alternately:
$ sudo systemctl stop wg-quick@wg0.service
Then edit the /etc/wireguard/wg0.conf
file to add several new Interface.PreUp
and Interface.PostDown
settings, like the following:
# /etc/wireguard/wg0.conf # local settings for Host β [Interface] PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA= Address = 10.0.0.2/32 ListenPort = 51822 # IP forwarding PreUp = sysctl -w net.ipv4.ip_forward=1 # firewall local host from wg peers PreUp = iptables -A INPUT -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT PreUp = iptables -A INPUT -i wg0 -j REJECT PostDown = iptables -D INPUT -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT PostDown = iptables -D INPUT -i wg0 -j REJECT # firewall other hosts from wg peers PreUp = iptables -A FORWARD -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT PreUp = iptables -A FORWARD -i wg0 -m state --state NEW -d 192.168.200.22 -p tcp --dport 80 -j ACCEPT PreUp = iptables -A FORWARD -i wg0 -j REJECT PostDown = iptables -D FORWARD -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -m state --state NEW -d 192.168.200.22 -p tcp --dport 80 -j ACCEPT PostDown = iptables -D FORWARD -i wg0 -j REJECT # clamp mss of tcp connections forwarded to wg peers PreUp = iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu PostDown = iptables -t mangle -D FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # remote settings for Host α [Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= Endpoint = 198.51.100.1:51821 AllowedIPs = 192.168.1.0/24
Then bring the interface back up again with wg-quick
or systemctl
:
$ sudo wg-quick up /etc/wireguard/wg0.conf
$ # or alternately:
$ sudo systemctl start wg-quick@wg0.service
This updated configuration will cause wg-quick
on Host β to add six new iptables
rules before it brings up the WireGuard interface, and remove the same rules after it brings the interface down.
The first two rules (added to the INPUT
chain) apply to traffic destined for Host β itself:
iptables -A INPUT -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -i wg0 -j REJECT
The first rule will accept all packets for already-established connections (ie connections that Host β initiated) coming through the WireGuard tunnel; and the second rule will reject anything else coming through the tunnel destined for Host β.
The middle three rules (added to the FORWARD
chain) apply to traffic forwarded through Host β to endpoints in Site B:
iptables -A FORWARD -i wg0 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i wg0 -m state --state NEW -d 192.168.200.22 -p tcp --dport 80 -j ACCEPT iptables -A FORWARD -i wg0 -j REJECT
Similar to the rules for the INPUT
chain, the first and third of the rules for the FORWARD
chain allow already-established connections, but reject new connections.
The second rule, however, will allow new TCP connections to be forwarded to port 80 of Endpoint B (192.168.200.22
in Site B). If you want to allow access to a different port of Endpoint B other than port 80 (like 8080), specify that port instead of 80. If you want to allow access to multiple ports of Endpoint B, adjust the rule slightly to use the multiport
match directive with the --dports
flag (note the trailing s
in --dports
) — like, for example, to allow both port 80 and 443:
iptables -A FORWARD -i wg0 -m state --state NEW -d 192.168.200.22 -p tcp -m multiport --dports 80,443 -j ACCEPT
The very last rule (added to the mangle
table’s FORWARD
chain) applies to traffic forwarded out of Host β from the endpoints in Site B:
iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
It automatically adjusts the MSS (Maximum Segment Size) option of TCP SYN and SYN-ACK packets forwarded out its WireGuard interface, to account for the interface’s lower MTU (Maximum Transmission Unit) size. This helps endpoints in Site A, at the other end of the TCP connections, to optimize the size of the packets they send to Site B, avoiding packet fragmentation.
Whenever you make changes to these rules, make sure you make the exact same change to both the PreUp
setting and its corresponding PostDown
setting (the PreUp
and PostDown
rules should be the same, just with a -A
flag for PreUp
and -D
flag for PostDown
). And if you use IPv6 addresses in your WireGuard VPN, substitute the ip6tables
command for iptables
in everything above.
Also note that when you’re fiddling with PreUp
and PostDown
settings, it’s best to bring the interface down first, make your configuration changes, and then bring the interface back up again (rather than making the configuration changes while the interface is still up, and then trying to restart afterward). The reason is that most of the time, your “Up” and “Down” settings are meant to be symmetrical (like add a firewall rule with PreUp
and remove it with PostDown
) — so if you change a PostDown
rule while your WireGuard interface is still running, you might inadvertently leave a stray firewall rule in place from the previous configuration version (which you’ll have to track down and clean up manually).
For tips on how to set up an iptables
firewall under a more complicated site-to-site scenario, check out the “Site to Site” section of the WireGuard Access Control With Iptables guide.
To use UFW to set up a firewall similar to the firewall described in this article, see the “Site to Site” section of the How to Use WireGuard with UFW guide; to use firewalld, see the “Site to Site” section of the How to Use WireGuard with Firewalld guide; or to use nftables, see the “Site to Site” section of the How to Use WireGuard With Nftables guide.