Post Notes: as of RouterOS 7.18 – ip – added support for /31 address
The steps below aim to illustrate how to setup a site to site VPN between two Mikrotik devices using WireGuard. Pre-existing local networks and firewalls exist on both R1 and R2. Between R1 and R2 the WireGuard tunnel will use 172.17.0.0/30. R2 has 172.17.0.1 assigned to its WireGuard interface, while R1 has 172.17.0.2 assigned to its WireGuard interface. The network used, or the order in which IP addresses are assigned is not important, however it is considered best practice to use a point to point subnet between peers.

The WAN IP addresses or “public” addresses we will use to run the tunnel over are the WAN addresses on each router. If your public IP’s are dynamic, I recommend using the built in DDNS service under IP > Cloud to ensure your endpoints are always reachable.
To start building out the VPN we need to configure each end of the tunnel, so I’ll start with R2. You can connect to either one of your Mikrotik devices and click on the WireGuard tab. If you don’t see it, you might need to upgrade to ROS v7 as WireGuard only came about being implemented with the release of v7.

Once inside the WireGuard menu, click on the + button to add a new interface. Give the new interface an appropriate name, or leave default and press ok. The default listen port is set to 13231, but you can change this if you like song long as it’s not conflicting with another running service. This is the destination port that will be used by your peers to establish the tunnel and the port that your router is listening for WireGuard connections on.
Once the interface has been created, a public key will be auto generated and will be visible if you open the interface up again. This is important for the peer settings later on.

Once the WireGuard interface has been created you must assign an IP address to it. Its up to you how you want to structure the routing, and what subnet to use. I’m going to be using 172.17.0.0/30 as my VPN subnet, so 172.17.0.1/30 will be assigned to this side of the tunnel, and 172.17.0.2 will be assigned to the peer.
Navigate to IP > Addresses > Address List. Once in the address list menu click on the + button to create a new IP address.

Enter the IP address and the CIDR notation. Leave the network section blank as the Mikrotik will automatically assign the network address. The interface this IP is assigned to is the WireGuard interface. Press apply, after that the network address will show up. Now press ok.

After completing the steps above log onto your other router, in my case this is R1 and replicate this setup there, the only difference will be the IP address you add to the WireGuard interface… Otherwise the steps are identical.
Once both of the routers you want to create a site to site VPN between have their WireGuard interfaces setup, we’re ready to move onto the next step.
In order for WireGuard to work we have to define the connecting peer details on either side of the tunnel. The connecting peer in this case would be both routers, R1 is R2’s peer, and R2 is R1’s peer. The WireGuard peer settings include a few things, most importantly the public keys for both ends of the tunnel so that encryption can function, as well as some connection controls.
On R2 I will define the details of R1: This is done in the WireGuard > Peers tab. Once in there Click on the + button to create a new peer.

On some newer versions of ROS you can define a name for the peer, do so if the option exists. If no option exists you can still add a comment on the peer if you like so that you know who it is. This is useful if you have multiple peers.
On the Interface field, If you have multiple WireGuard interfaces you can select which one this peer is expected to connect to. If you only have one WireGuard interface then it will default to that interface.
The Public Key field in R2’s peer settings needs to be R1’s WireGuard interface public key.

The Endpoint is R1’s public IP address. DDNS can be used here quite easily especially if its two Mikrotik devices as they support DDNS natively in the IP > Cloud menu. Simply paste the DDNS address in the Endpoint field instead of an IP address.
The Endpoint Port will be the listen port set on R1’s interface, so 13231.
Allowed Address defines an IP address or entire subnet that is allowed to reach the WireGuard interface through this peer e.g R1 will be able to send traffic to R2 over the tunnel as long as it originates from 172.17.0.2/30 – This is also where we’ll be setting the LAN ranges later. Notice the downward facing arrow next to allowed address, that allows you to create a second field to define a second IP address or subnet.
Preshared Key if you want to. It just needs to be the same on both ends. If you do want to, I suggest setting this to Auto and then copying it onto the other sides peer once we get round to setting that up.
Persistent Keep Alive keeps the tunnel open for the defined amount of time if the connection on either end fails. I have set this to 10 seconds.
Repeat these steps almost exactly on R1, just instead of using R1’s public key in the peer, use R2’s and instead of defining 172.17.0.2/30 as the allowed address, use 172.17.0.1/30.

At the absolute minimum assuming that some sort of firewall exists and is blocking external connections in from the outside, an exclusion will need to be made for WireGuard to establish a tunnel. Its important to mention that once the tunnel is up, any traffic going over that tunnel, once received and decapsulated will be treated as regular traffic and an exclusion will be required for any source addresses not explicitly allowed.
Because I don’t know what your firewall looks like, I can’t guide you exactly on how to achieve this next step, but I’ll show you a generic approach that should suffice for most.
WireGuard uses UDP and as per our settings port 13231, so I’m first going to allow input from UDP port 13231 on both of my routers. Go to IP > Firewall > Filter Rules.

Click the + button to add a new filter rule. In the General tab set the chain to input.

Set the protocol to UDP and the Dst port to 13231. Leave everything else blank, or add any relevant fields to further limit the scope of this filter. The way I have it setup now will allow anything to reach the WireGuard interface on any interface. In general when using Mikrotik ROS, leaving a filed blank typically means that it applies to everything/everywhere or that it will inherit some sort of default config e.g the Src Port field is left blank here, therefore any source port will be accepted because it wasn’t defined.

Skipping over all the other tabs and heading straight to Action, select accept from the drop down menu and click ok.

Mikrotik firewall filters are implemented sequentially from top to bottom so we need to drag our new input filter up above any filters that might affect that traffic before it reaches the input allow filter that we created for the WireGuard VPN.

Next we can create another filter rule to allow forwards over the WireGuard tunnel so that traffic coming over from R1 will be able to to reach hosts behind R2.
To do this click on the + button again in the firewall filter rules. Select the forward chain and your WireGuard interface as the In. Interface.

Jump to the action tab and select accept from the drop down menu, then click ok. Remember to drag this rule up high enough up so that it impacts the intended traffic. I recommend dragging it under the input rule we made above.

Now go and duplicate this on your other router, the config is exactly the same.
Assuming all of the steps have been correctly implemented and there are no firewall rules blocking the connection, you should now have a WireGuard tunnel up and running with regular handshakes. You should even be able to ping across the tunnel and hit each end point from the opposing peer. If you can’t, check if your firewall is dropping ICMP, alternatively you can add an input rule to accept input from traffic coming in on the WireGuard interface. That will allow access to the router from any network coming in on the VPN tunnel, so you may want to lock it down further and specify the tunnel subnet only.

Now lets setup our routing. By default there won’t be any routes to any of the networks sitting behind our two routers so neither of them will know where to send traffic destined for each others LAN subnets. To fix this we can add static routes.
On R1 we have the 192.168.87.0/24 LAN network and on R2 we have the 192.168.89.0/24 LAN network. We are going to add a route on either side telling each router how to reach the others LAN networks:
On R2 we go to IP > Routes to open the route list.

Click on the + button to add a new route. The Dst. Address is 192.168.87.0/24 (R1’s LAN) – The Gateway is 172.17.0.2 (R1’s WireGuard interface IP). Next click ok to add the route.

R2 now knows that if it needs to send traffic to 192.168.87.0/24 the gateway there is 172.17.0.2. The router already knows how to reach 172.17.0.2 because a dynamic route will exist for 172.17.0.0/30 that ROS added to the WireGuard interface after adding an IP and subnet to it.
On R1 Add the route to R2’s LAN network with the gateway pointing to R2’s tunnel end point (172.17.0.1).
Once you’ve added the static routes you need to allow traffic for the LAN subnets by adding them to the allowed addresses on the respective WireGuard peers. Without this, traffic will not be able to flow from the LAN ranges over the VPN. For example, if I ping 192.168.87.1 from 192.168.89.1, the return traffic will have the the source IP address 192.168.87.1 – If I’m not explicitly allowing traffic with that subnet as its source back in on the WireGuard peer on R2, it will be dropped.
Lets configure this by going to WireGuard > Peers > Add the LAN subnet to the allowed address and press ok. This has to be done on both ends, as I’m sure you guessed. Make sure to allow the R2’s LAN subnet on R1’s peer settings for R2.

Assuming the routes and allowed IP’s have been setup correctly and no firewall rules are blocking it, you should be able to ping across.

In terms of a basic setup, that’s about it for WireGuard without natting.
NAT:
The rest of this post will be on NAT, how to implement it for your VPN and why you may or may not need it. If you don’t need NAT, feel free to consider your Site to Site VPN done 🙂
Lets consider our network design and think about NAT. If no NAT rules exist for traffic traversing the VPN, any traffic sent over the tunnel will have the original senders IP address as the source address. Having NAT setup can simply routing and firewalling significantly, especially in larger more complex networks. A typical NAT setup would translate all traffic going over the tunnel to whatever the tunnel endpoint IP is, e.g. if traffic were to leave R2, we could NAT that traffic to make its source address 172.17.0.1 – And similarly on the other side of our tunnel we’d do the same.
I’m going to run a ping to R1 from R2, specifying the source address to be from the LAN segment.

Torching the WireGuard interface on R1 shows me that ICMP traffic is coming in with a source IP of 192.168.89.1. This is expected.

Lets now setup NAT, so that any traffic coming in to R1 will look like its coming from R2’s WireGuard endpoint (172.17.0.1). Go to IP > Firewall > NAT.

Before setting up the NAT rules, I will create an address list consisting of R1’s networks. I’ll use this later to define the destination for the NAT rule. Go to the Address List tab, and click the + button to add a new address list. Add in the endpoint IP for R1, and click ok.

Click the + button again, this time select the VPN list used previously from the drop down menu. Add in the LAN subnet for R1 and press ok.

Moving back to the NAT tab, click on the + button to add a new NAT rule. In the General tab, specify the chain as srcnat, and choose your VPN address list from the Dst. Address List from the drop down menu.

In the Action tab, select src-nat as the action, and the the To Address the WireGuard IP endpoint for R2. This will be 172.17.0.1, then press ok.

What this has done is told the router that whenever traffic is destined for R1’s networks, translate the source address to 172.17.0.1, essentially hiding all traffic behind the WireGuard interface IP. This means that R1 sees all VPN traffic coming exclusively from R2’s WireGuard interface. This is useful to simplify routing and firewalling.
Lets test it out. I’m going to run a ping to R1 explicitly specifying the source address to be from 192.168.89.1. Once I start the ping, you can see the NAT rule doing something because the byte counter is going up.

Torching the WireGuard interface on R1 again, and we see that someone is pinging us, however the source address is 172.17.01. Even though we explicitly told R2 to ping R1 from 192.168.89.1, the router translated the traffic before sending it out, and to R1 everything seems to be coming from 172.17.0.1. R1 will respond to R2, and then R2 will send the traffic to its original source using its NAT table.

This NAT rule can be setup on R1 with R2’s networks to have a fully NATTED VPN network. With NAT setup and working correctly, we also don’t need to add in specific allowed addresses to the WireGuard peer, only the end point of the other router.

