Trouble with port forwarding through a Wireguard VPN

Hello, I have a strange situation where my ISP does not give me a public IPv4 address, only a private IPv4 address. I would like to port forward services such as Minecraft and SSH, so I purchased a Linode VPS and have set up a Wireguard VPN tunnel on it. I was able to successfully get the VPN link between the Linode and my MikroTik hap ac2 router to work, and have no issues communicating with devices on my network with it.

While I was able to get this to work, I’ve noticed that traffic that is port forwarded through the VPN has a source address of 172.16.255.1, which is the IP address of the wg0 interface on my Linode. I would like to see the client’s actual IPv4 address. I believe this is due to me needing to set up a masquerade rule in nftables on the Linode. I was only able to get it to work this way, so I suspect there may be a configuration error on my MikroTik router. Is there anything I can do to resolve this issue on my router, or is it a configuration issue on the Linode side? From what I’ve read, I may need to configure some routing policies on the client device (mikrotik) so it knows to send traffic back through the VPN.

For reference, here is the traffic flow and relevant IP addresses:

Linode VPS public IPv4 → WireGuard tunnel → hap ac2 → private ip address range

So, for example if port 25565 is forwarded to 192.168.10.20:25565, 192.168.10.0/24 has a route that goes through the VPN to my router.

IP addresses:
Linode wg0: 172.16.255.1/30
hap ac2 wireguard1: 172.16.255.2/30
LAN: 192.168.10.0/24

Below is my current configuration that is pertinent to the VPN. If you need the full configuration, I can provide it if needed. Note that in the configuration there is only the default NAT masquerade rule, and wireguard1 is not part of the WAN interface list. So no NAT should be performed between the VPN and LAN subnet.

/interface wireguard
add listen-port=12755 mtu=1420 name=wireguard1

/interface list member
add interface=bridge list=LAN
add interface=ether1-wan list=WAN

/interface wireguard peers
add allowed-address=0.0.0.0/0 comment="Wireguard tunnel to Linode" endpoint-address=<Linode public ip> endpoint-port=51820 interface=wireguard1 persistent-keepalive=30s public-key="<Linode pubkey>"

/ip address
add address=192.168.10.1/24 interface=bridge network=192.168.10.0
add address=172.16.255.2/30 comment="Site to site VPN" interface=wireguard1 network=172.16.255.0

/ip firewall address-list
add address=192.168.10.20-192.168.10.25 comment="Virtual machines" list=allowed_from_vpn
add address=192.168.10.10 comment="Proxmox host" list=allowed_from_vpn

/ip firewall filter
add action=drop chain=forward comment="Only allow VPN to access specific hosts on LAN" dst-address-list=!allowed_from_vpn in-interface=wireguard1
# note: this firewall rule is to prevent the linode from accessing devices outside of ones specifically allowed. I intend to place these devices in their own vlan eventually... the rule works and hopefully shouldn't be causing any issues.

# Default NAT rule
/ip firewall nat
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN

nftables configuration:

table ip nat {
        chain prerouting {
                type nat hook prerouting priority dstnat; policy accept;
                iif "eth0" tcp dport { 8091, 25565 } dnat to 192.168.10.20

                iif "eth0" udp dport { 19132 } dnat to 192.168.10.20
        }

        chain postrouting {
                type nat hook postrouting priority srcnat; policy accept;

                # DNATted traffic is masqueraded -- I would like to get rid of this so I see the real ipv4 address in connection logs 
                ct status dnat masquerade;
        }
}

Any help is appreciated! Let me know if you need anything else. Thank you so much in advance.

You’re looking for something like this:

/routing table
add name=wg fib
/ip route
add dst-address=0.0.0.0/0 gateway=wireguard1 routing-table=wg
/ip firewall mangle
add chain=prerouting in-interface=wireguard1 connection-mark=no-mark action=mark-connection new-connection-mark=wg-conn
add chain=prerouting in-interface=bridge connection-mark=wg-conn action=mark-routing new-routing-mark=wg
add chain=output connection-mark=wg-conn action=mark-routing new-routing-mark=wg

Basically you need to treat WG as another WAN interface, mark incoming connections from there and route responses back the same way.

WHy not use BTH wireguard and dispense with the VPS.

However, SOB, I dont get your solution? How is the OP going to see the public IP address of the incoming port forwarded traffic landing at the MIkrotik which I think was his question?

Masquerade on server side will have to be removed, of course. But that alone would break it and it wouldn’t work at all. With this config it will. It’s the good old “forwarding port through VPN”, you know that.

Again, do you mean port forwarding done at the VPS or done once the traffic arrives at the MT.

I guess i dont get why doesnt the client go through WG and straight to the device in question???
The old firewall forward chain :slight_smile:

Sob, thank you so much! That resolved the issue, and I am now seeing the real source IP address in tcpdump and my Minecraft server. While this worked, it was only part of the solution. The default fasttrack firewall rule was causing issues where clients would connect but time out after connecting. I modified the fasttrack rule to only apply to packets without a connection mark. I did this in lieu of completely disabling fasttrack, as I need the hardware offloading. Was I right to do this? I am on a symmetrical gigabit connection.

/ip firewall filter
add action=fasttrack-connection chain=forward comment=“fasttrack established, related connections that do NOT have a connection mark” connection-mark=no-mark connection-state=established,related hw-offload=yes

I did make one other change to the mangle rules to use an interface list instead of hardcoding the bridge interface. I am going to be setting up VLANs on my router soon, so this will be in preparation for that. The mangle rule is now as follows: add action=mark-routing chain=prerouting connection-mark=wg-conn in-interface-list=LAN new-routing-mark=wg passthrough=yes


I need the services I am running publicly accessible on the internet. From my understanding of the Back To Home VPN, it is used so you can access your home network remotely using a VPN client. Since I am behind NAT, traffic is going to be forwarded through MikroTik servers and I’m not sure if they have the available bandwidth or a server close enough to my location which would affect latency. With the Linode VPS, I picked a geographically close datacenter and get an average latency of about 15ms between my router and the Linode.

What can I say, you know what you’re doing. Gentle push was enough.

@anav: It’s when you don’t have public IP address from your ISP, but you want one. So you get it elsewhere (VPS) and then forward ports from there.

Without a network diagram Im a tad lost. Using linux at the VPS is of no help either…

He wants to see originating IP address at the VPS or at the MT device???
Thus port forwards the traffic from there with destination address to his servers which are actually at the MT.
So he needs port forwarding on VPS is to indicate to-address= IP address of subnet device on MT.
AND static route, dst-address=device subnet gateway=wireguard1 table=main

In other words the users are NOT coming in on wireguard to the VPS to reach the servers they are coming in plain…

Allowed IPs on VPS wg need only be the subnets on MT and the wireguard IP/32 of the MT.
Allowed IPs on MT could easily set on 0.0.0.0/0 and thus accept any incoming source address.
Thus need firewall rule forward chain allowing traffic from wireguard1 to the device subnet or to a list of devices only (better)

So as stated the traffic coming in over wireguard from the VPS will be coming and exiting the MT and allowed by wg filtering
Thus we have to ensure the return traffic, potentially to any public IP out there, will go back out the tunnel and not be confused with that similar looking traffic going out local WAN.
/routing table add fib name=useWG
/ip route
add dst-address=0.0.0.0/0 gateway=wireguard1 routing-table=useWG

/ip nat mangle
add chain=prerouting action=mark-connections connection-mark=no-mark
new-connection-mark=incoming-WG passthrough=yes in-interface=wireguard1
add chain=prerouting action=mark-routing connection-mark=incoming-WG
new-routing-mark=useWG passthrough=no

I was with you till you posted the output chain rule… There is no traffic from the router itself we need to be concerned with ???

I came up with two other variations, for fun but they dont add much in this case…

/ip nat mangle
add chain=prerouting action=mark-connections connection-mark=no-mark
new-connection-mark=incoming-WG passthrough=yes in-interface=wireguard1
add chain=prerouting action=mark-routing connection-mark=incoming-WG
src-address-list=SERVERS new-routing-mark=useWG passthrough=no

/ip nat mangle
add chain=prerouting action=accept in-interface-list=LAN dst-address-list=SERVERS
add chain=prerouting action=mark-connections connection-mark=no-mark
new-connection-mark=incoming-WG passthrough=yes in-interface=wireguard1
dst-address-list=SERVERS
add chain=prerouting action=mark-routing connection-mark=incoming-WG
new-routing-mark=useWG passthrough=no

Traffic coming from tunnel can be to:

a) some device behind router → route marking for responses is done in prerouting
b) router itself → route marking for responses is done in output

As for different variants of the rules, don’t overthink it. You need one to mark incoming connections and you can’t do much with that. And second to mark routing for responses (not counting the output one if you need to deal with traffic to router itself). There you can use in-interface=LAN, in-interface-list=LANs, or in-interface=!WG would work too, because if it’s from anywhere else and it has the mark, it must be response.

Disagree, the traffic being discussed is very specific, its outside user, port forwarded at VPS into the tunnel to servers on MT device.
There is no user that will be coming into VPS on a public IP (not in tunnel) being directed to the MT config aka to the router itself.
Magic mushrooms for xmas??

What could transpire is the admin coming into the VPS remotely INSIDE a wireguard tunnel and then going to the router and this would be handled internally via existing wireguard nomenclature DAC routes etc..

So if you want to show me where my thinking is wrong, I will gladly be proven wrong!!

Yes, original post was about forwading ports to another device behind router, and you don’t need the output rule for that. But it’s related, so why not cover even possible future needs right away? Worst case, it won’t be used. Maybe after seeing how great these forwarded ports work, next requirement may be for accessing something on router, i.e. forwarding another port to router itself. And then it will just work, if the output rule is already there.

Now your making up crap…
There is no need in this scenario, and no clear future need for the output chain in a future scenario from incoming Wireguard traffic from the other Device.
If one was to have WG incoming to this router perhaps… So instead of exiting gracefuly from this thread, will have to kick you out … BOOT !!

It’s perfectly reasonable. When you have this “remote public address” that you use to forward ports from there to devices in your LAN, then the router possibly being one of those devices is not any far fetched idea. I can’t come with with any good analogy right now, but trust me, it makes sense. :slight_smile:

I trust you to apply an excellent config for a specific purpose.
However, this is not the case, you have invented a requirement not requested, likely to never be requested and it only ends up confusing people trying to learn.

The bottom line is the output chain rule is not needed here.

For anybody reading this thread, the output chain is very useful and as stated is to ensure traffic arriving on the WAN SIDE or any other side ( but mostly WAN side ) that is TOO the router (too router services) example wireguard handshake, is routed back out the same way it came in.

When could this happen?
Ex. One has two wans WAN1 is primary and WAN2 is secondary. The router is acting as wireguard server for the handshake. The Admin wants the Wireguard to come in on WAN2.
Without the Mangle, and Output rule in place the client device will request a handshake coming in on WAn2, the response will go out WAN1 and the handshake will not occur.

The key to remember:
OUTPUT chain is used for responses from the Router itself (not anything on the LAN)