double-hop Wireguard

Hi everyone,

I’m running a central WireGuard server on a MikroTik CHR (10.20.30.1) and have five “clients” and three “users” all peered directly to it. By default everyone’s traffic is NAT-ed out via the CHR’s public IP. What I’d like to do is give two of my users a “double-hop” so they egress with the public IP of a specific client.


                        +------------+
                        |  Internet  |
                        +-----+------+
                              |
                           [ CHR ]
                       WG @ 10.20.30.1
                              |
        ---------------------------------------------------------
        |      |      |      |      |       |       |       |
      [C1]   [C2]   [C3]   [C4]   [C5]   [U1]   [U2]   [U3]
       WG@    WG@    WG@    WG@    WG@    WG@    WG@    WG@
       .101   .102   .103   .104   .105   .201   .202   .203



  • CHR (10.20.30.1) is the central WireGuard endpoint.
  • Clients C1–C5 each have WG IPs 10.20.30.101–.105 and peer to CHR.
  • Users U1–U3 each have WG IPs 10.20.30.201–.203 and peer to CHR.


On every peer:
[Peer]
PublicKey = <CHR pubkey>
AllowedIPs = 0.0.0.0/0
Endpoint = <CHR public IP>:51820
PersistentKeepalive = 25

CHR’s WG interface also has:
[Peer]
PublicKey = <each-client pubkey>
AllowedIPs = <peer’s WG IP>/32



  • CHR is NAT-masquerading all wg-traffic out to the Internet (etho1 is masquerade in NAT), so all peers appear as CHR’s public IP.

Desired behavior

  • User 1 (10.20.30.201)
  • Still peers to CHR.
    • Traffic from U1 should be forwarded to Client 1 (10.20.30.101) on the CHR box, then NAT’d out via C1’s public IP.
  • User 2 (10.20.30.202)
  • Similarly should egress via Client 2 (10.20.30.102) and thus use C2’s public IP.
  • User 3 (10.20.30.203) and Clients 3–5 remain untouched and continue to egress directly via the CHR’s public IP.

What I’ve tried

  • Adding static routes on CHR pointing 10.20.30.201 → 10.20.30.101 / 10.20.30.202 → 10.20.30.102
  • Policy-based routing / mangle rules to mark packets by source IP, then routing table lookups.

Both of it works only if i add 0.0.0.0/0 in the CHR Peers allowed address but then it overlaps and only the first connected peer works for the routings

Questions

  • How can I configure CHR (RouterOS) to forward U1’s WG-tunnel traffic through the C1 tunnel and then NAT it on C1’s WAN?

Limitations

  • I can only have One WG interface in the CHR.

It should be possible with routing rules without messing with the allowed addresses of the peers on the CHR: create two new routing tables, add the respective default routes in them and add routing rules:

/routing table
add fib name=to_C1
add fib name=to_C2

/ip route
add dst-address=0.0.0.0/0 gateway=10.20.30.101 routing-table=to_C1
add dst-address=0.0.0.0/0 gateway=10.20.30.102 routing-table=to_C2

/routing rule
add action=lookup-only-in-table src-address=10.20.30.201 table=to_C1
add action=lookup-only-in-table src-address=10.20.30.202 table=to_C2

i just tried with the routing table method (U1 to C1) but i still dont see U1 getting internet and also in C1 I dont see the requests from U1

May I have a look at your full config? Maybe there is some firewall rule that is too strict or something else blocking traffic between clients:

/export file=anynameyouwish (minus sensitive info)



/ip firewall address-list
add address=192.168.120.0/23 list=RemoteLANs
add address=192.168.140.0/23 list=RemoteLANs
add address=192.168.150.0/23 list=RemoteLANs
add address=10.20.30.51 list=RemoteAdmins
add address=10.20.30.52 list=RemoteAdmins
add address=10.20.30.2 list=RemoteAdmins
add address=10.20.30.0/24 list=LocalSubnets
/ip firewall filter
add action=accept chain=forward comment="Allow RemoteAdmins to access RemoteLANs" disabled=yes dst-address-list=RemoteLANs src-address-list=RemoteAdmins
add action=drop chain=forward comment="Drop Non RemoteAdmins to access RemoteLANs" disabled=yes dst-address-list=RemoteLANs src-address-list=!RemoteAdmins
/ip firewall mangle
add action=change-mss chain=forward comment="Clamp MSS to PMTU for WireGuard packets" new-mss=1344 protocol=tcp tcp-flags=syn
add action=mark-connection chain=prerouting comment="Connection Mark for Non-LocalSubnets" dst-address-list=!LocalSubnets in-interface=CognitiveSystems_WireGuard new-connection-mark=non-localsubnet
add action=mark-routing chain=prerouting comment="Routing Mark for RemoteLANs" connection-mark=non-localsubnet dst-address-list=RemoteLANs in-interface=CognitiveSystems_WireGuard new-routing-mark=RemoteLANs
add action=mark-routing chain=prerouting comment="Routing Mark for VPN_BD" connection-mark=non-localsubnet disabled=yes in-interface=CognitiveSystems_WireGuard new-routing-mark=VPN_BD src-address=10.20.30.201
/ip firewall nat
add action=dst-nat chain=dstnat comment="WireGuard_Grabbers_qBittorrent - UDP" dst-port=42024 in-interface=ISP protocol=udp to-addresses=10.20.30.101 to-ports=42024
add action=dst-nat chain=dstnat comment="WireGuard_Grabbers_qBittorrent - TCP" dst-port=42024 in-interface=ISP protocol=tcp to-addresses=10.20.30.101 to-ports=42024
add action=src-nat chain=srcnat comment=MikroTik_Essen dst-address=10.20.30.2 to-addresses=10.20.30.1
add action=dst-nat chain=dstnat dst-port=61201 in-interface=ISP protocol=tcp to-addresses=10.20.30.2 to-ports=58291
add action=src-nat chain=srcnat comment=MikroTik_MockingBird dst-address=10.20.30.3 to-addresses=10.20.30.1
add action=dst-nat chain=dstnat dst-port=61301 in-interface=ISP protocol=tcp to-addresses=10.20.30.3 to-ports=58291
add action=src-nat chain=srcnat comment=MikroTik_Haus_Boehm_1 dst-address=10.20.30.4 to-addresses=10.20.30.1
add action=dst-nat chain=dstnat dst-port=61401 in-interface=ISP protocol=tcp to-addresses=10.20.30.4 to-ports=58291
add action=src-nat chain=srcnat comment=MikroTik_Haus_Boehm_2 dst-address=10.20.30.5 to-addresses=10.20.30.1
add action=dst-nat chain=dstnat dst-port=61501 in-interface=ISP protocol=tcp to-addresses=10.20.30.5 to-ports=58291
add action=masquerade chain=srcnat comment="Masquerade ISP" out-interface=ISP routing-mark=!VPN_BD
add action=masquerade chain=srcnat comment="Masquerade CognitiveSystems" disabled=yes out-interface=CognitiveSystems_WireGuard
/ip firewall raw
add action=drop chain=prerouting comment="Drop all IPs from BannedIP list" in-interface=ISP src-address-list=BannedIP
add action=drop chain=prerouting comment="Drop all DNS queries on ISP - UDP" dst-port=53 in-interface=ISP protocol=udp
add action=drop chain=prerouting comment="Drop all DNS queries on ISP - TCP" dst-port=53 in-interface=ISP protocol=tcp

i wish to route 10.20.30.201 through 10.20.30.2


FYI 10.20.30.2 can ping 10.20.30.201 and vice versa

Do you have another device that acts as a firewall because with the rules that are presented in the config (which is not full, hence errors that are not visible could be elsewhere) the access to the router and the devices behind it from outside is as free as a bird. Also, mangle and routing rules don’t work nice together.

no this chr is hosted in a barebone without any firewall… also i am using mangle only… no table… i tried with the table mode but same… the whole thing works when i add 0.0.0.0 in the peer allowed addess

Before doing anything else, implement the default firewall at least:

/ip firewall filter
add chain=input action=accept connection-state=established,related,untracked comment="defconf: accept established,related,untracked"
add chain=input action=drop connection-state=invalid comment="defconf: drop invalid"
add chain=input action=accept protocol=icmp comment="defconf: accept ICMP"
add chain=input action=accept dst-address=127.0.0.1 comment="defconf: accept to local loopback (for CAPsMAN)"
add chain=input action=drop in-interface-list=!LAN comment="defconf: drop all not coming from LAN"
add chain=forward action=accept ipsec-policy=in,ipsec comment="defconf: accept in ipsec policy"
add chain=forward action=accept ipsec-policy=out,ipsec comment="defconf: accept out ipsec policy"
add chain=forward action=fasttrack-connection connection-state=established,related comment="defconf: fasttrack"
add chain=forward action=accept connection-state=established,related,untracked comment="defconf: accept established,related, untracked"
add chain=forward action=drop connection-state=invalid comment="defconf: drop invalid"
add chain=forward action=drop connection-state=new connection-nat-state=!dstnat in-interface-list=WAN comment="defconf: drop all from WAN not DSTNATed"

Plus an input accept rule for Wireguard placed before the drop all not coming from LAN input one:

/ip firewall filter
add action=accept chain=input dst-port=51820 protocol=udp

done with that btw the port for wg is 369 for my case not 51820.. i disabled all the mangles and now got only the routing rule and table… what i see is thta if i activate the routing rule the user is loosing internet but if i turn off then it gets internet but from the CHR public


Route

/ip route
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=10.10.10.1 routing-table=main scope=30 suppress-hw-offload=no target-scope=10
add comment=RemoteLANs disabled=no distance=1 dst-address=0.0.0.0/0 gateway=CognitiveSystems_WireGuard routing-table=RemoteLANs scope=30 suppress-hw-offload=no target-scope=10
add comment=VPN_BD disabled=no distance=1 dst-address=0.0.0.0/0 gateway=10.20.30.102 routing-table=VPN_BD scope=30 suppress-hw-offload=no target-scope=10

Here is the full config
config.rsc (10.7 KB)

have you tried defining default gateway within wg for u1 & u2, as respectively c1 & c2?

hence routes that get pushed to the wg peers:
https://help.mikrotik.com/docs/spaces/ROS/pages/69664792/WireGuard#WireGuard-Peers

Okay as I see it you want something very complex
There is no point in looking at the config at the moment.
What is needed, excuse my overexhuberant colleagues is a concrete plan and understanding of the requirements.
IS what you are asking possible. Likely, so how do we get there.
What are the limiting factors of wireguard usually in such matters one has to only look at ALLOWED ADDRESSES.
One basic rule of thumb is that if you have internet access in one direction (0.0.0.0/0) but also what internet access in the opposite direction, you are barking up the wrong tree using only one interface.
HENCE yes, its possible but you will need multiple wireguard interfaces.

Basic understanding
First, is for some use of the CHR as an internet source
Secondly and more complex, you want a user1 to connect to the CHR ( but only as a relay ) and send all their traffic out the Internet of Client Router1 ( I will assume its a mikrotik router for understanding purposes ).


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Now a standard approach of one interface RUNS into a problem.
The allowed IPs ( peers settings on the CHR) for each device is singular ( only the wireguard IP/32 is used ).
If you have trouble understanding this, imagine if you have five peer settings and all have allowed IPs of 0.0.0.0/0
The router will match Always for all traffic the first peer and never this the remaining four!~~~

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Conclusion you need to have a second wireguard interface between each CLient Router and CHR. This means one main interface for all Client Routers to CHR for internet out CHR.
First one takes care of internet traffic via CHR
Second takes care of internet traffic out CLient Router ( so as many additional wg interfaces on the CHR as there are Client Routers )

Assume main wireguard subnet is 10.10.10.0/24
Assume secondary wireguard subnets are 10.10.11.0/24 (CR1) / 10.10.21.0/24 (CR2), 10.10.31.0/24 (CR3) etc…

CHR peer settings
Interface wgchrmain - Allowed IPs= 10.10.10.11/32 ( client router 1)
Interface wgchrmain - Allowed IPs= 10.10.10.12/32 ( client router 2)
Interface wgchrmain - Allowed IPs= 10.10.10.13/32 ( client router 3)
etc…
PLUS
Interface wgchr-cr1 - Allowed IPs= 0.0.0.0/0 ( client router 1) ( address=10.10.10.11/24 ) ( client router 1)
Interface wgchr-cr2 - Allowed IPs=0.0.0.0/0 ( client router 2) ( address=10.10.10.12/24 ) (client router 2)
Interface wgchr-cr3 - Allowed IPs= 0.0.0.0/0 ( client router 3) ( address=10.10.10.13/24 ) (client router 3 )
etc…
+++++++++++++++++++++++++++++++++++++++++++++++
CHR IP addresses
address=10.10.10.1/24 ( interface wgmain)
address=10.10.11.1/24 ( interface wg-cr1)
address=10.10.21.1/24 ( interface wg-cr2)
address=10.10.31.1/24 ( interface wg-cr3)
+++++++++++++++++++++++++++++++++++++++++++++++++++


Client Router 1 peer settings
interface=wgmain allowed-ips=0.0.0.0/0 ( outgoing local traffic to CHR for internet )
interface=wg-cr1 allowed-ips=10.10.11.0/24,10.10.10.0/24 ( from CHR external user1 use of local internet )

Client Router 1 Addresses
interface=chrmain address=10.10.10.11/24
interface=wr-cr1 address=10.10.11.2/24

Client Router 2peer settings
interface=wgmain allowed-ips=0.0.0.0/0 ( to CHR MAIN )
interface=wg-cr2 allowed-ips=10.10.21.0/24

ip address
interface=chrmain address=10.10.10.12/24
interface=wr-cr1 address=10.10.21.2/24

Client Router 23peer settings
interface=wgmain allowed-ips=0.0.0.0/0 ( to CHR MAIN )
interface=wg-cr3 allowed-ips=10.10.31.0/24

ip address
interface=chrmain address=10.10.10.13/24
interface=wr-cr3 address=10.10.31.2/24

Necessary routes for traffic to enter tunnels, necessary routes for return traffic etc.
Necessary firewall rules to allow traffic to enter tunnels for specific destinations
Necessary firewall rules to allow traffic to exit tunnels for specific destinations

++++++++++++++++++++++++++++++++++++++++++
In terms of users, as per my iphone I can have multiple wireguard settings.
One for connecting to CHR for internet given an IP address of 10.10.10.XX
One for connecting to CHR to relay to Client Router X for internet given an IP address of 10.10.11.X

Yes what you mentioned I did that and worked but I wanted something with single interface with the same ip subnet 10.20.30.x for both the two way internet… mainly to have clean interfaces and single subnets one limit I got that I gave to have a constant Udp port for all wg connections ( 1 interfaces or more all needs to be on the same port)

Correct instead of stating what the router should do according to your wishes in terms of functionality.
Better to describe the traffic flow requirement for all identified users and devices.
From that a config will take shape.
So yes exactly knowing how wireguard works, would tell you that two way internet from chr to multiple external users is not possible without multiple interfaces.