Port Forwarding with custom VPN routes

I’m a bit out of my depth here with what I’m trying to accomplish. I could be crazy and someone just tell me not possible. But if possible, I would like to find a solution.

I have a wireguard interface connected to a VPN provider. I don’t control the VPN providers network, so when I am using that connection, the IP that I appear as on the internet is out of my control.

I created VLAN5 to use to send traffic over the VPN provider.

I created a routing table so that any traffic not destined for an internal IP, and has VLAN5, should be sent to that routing table, rather than main (which goes out my ISP).

All works as expected.

What I tried to do was create port forwarding to allow incoming connections to be forwarded to machines that use VLAN5. But the incoming traffic has to come to my ISP’s provided public IP. Because the VPN’s public IP does not come to my router. So I can’t handle it.

I setup nat destination and a firewall rule to allow it. The port forwarding works. Watching tcpdump on the internal client, I see the incoming data.

But, I never see any response on the outside machine trying to get in.

I’m assuming this is because the data comes in to IP 1. And my machine sends a response which has VLAN5 tag, so VyOS sends it out of IP 2. And the data either never meets or because the responding IP is different than where the client originally sent the connection to, it is ignored/dropped.

Any ideas how to allow for this?

It’s not really clear to me what you’re trying to do - you talk about incoming connections but you don’t say which interface (Your ISPs? Wireguard?) they’re coming in on.

Are you trying to have someone hit the IP of your wireguard interface and get port forwarded, i.e. expose a service on yor Wireguard interface?

What you mean “VLAN5 tag” exactly? Are you able to draw a diagram or something?

Are you using policy based routing, is that what you mean by “I created a routing table so that any traffic not destined for an internal IP, and has VLAN5, should be sent to that routing table, rather than main (which goes out my ISP).” ?

I’m sure what you want to do is possible, but I can’t follow your traffic flow(s) and how you’re acheiving them.


As written above. There are some questions open. In theory you can do dnat on a wireguard interface like on an normal ISP Interface.

If your internal host should be reachable from isp and wireguard. The easiest way would be to habe there two interfaces. Or one and a vlan5 sub interface so the responses packages can be routed according to the vlan and NAT can do it’s thing.

I tried to draw a diagram, but I’m horrible at it and… yeah. I spent more time in the weeds and here’s my issue.

IPv4 Only.

I have interfaces:

  • ETH0 <isp_public_ip>

  • WG0 <vpn_public_ip> (Technically this has an internal IP for the wireguard network but the other end is natting to a public ip owned by the vpn provider).

  • LAN0

  • LAN1

ETH0 is a static IP from my ISP and all traffic out of this interface is natted. That IP always routes to my VyOS.

WG0 connects to a VPN service that has a changing public IP and all traffic out of this interface is natted. That IP never routes to my VyOS.

External destined traffic received by VyOS on LAN0 is forwarded out through ETH0.

External destined traffic received by VyOS on LAN1 is forwarded out through WG0.

Problem 1:
My internal host is on LAN1. The service I run does both establishes outbound requests and opens a tcp port (12345) for listening in order to receive inbound requests. Port is configurable.

The hosts on the remote side are made aware that my host that is listening for connections by inspecting the IP address that I am connection from.

In this case, the remote service sees <vpn_public_ip>, because I am natted behind that.

So, hosts on the remote side attempt to connect to <vpn_public_ip>:12345, and I never see that traffic and their connection fails.

I guess, I would have to be able to tell that service that even though I am coming to you from <vpn_public_ip>, I want you to connect to me at <isp_public_ip>. That would be problem 1.

Problem 2:
Let’s say I could solve problem 1 and notify the service of my true IP for incoming connections.

Now, a connection request comes to my router at the <isp_public_ip>:12345, the DNAT rule picks it up and forwards to the internal host But now, the host is going to send a reply of some sort, and my router is going to push that reply outbound through WG0, which will then be natted to <vpn_public_ip>. So the original sender sends a request to <isp_public_ip> but a response packet is coming from <vpn_public_ip>.

Would that work? Is Problem 2 a real issue or am I thinking incorrectly about it?

Since my reply is not a new connection, would the static route not come in to play? And would it route out over the interface the original request was received on?

EDIT: I setup a test using ICMP. I got the nat and firewall rule in place. Ran TCP dump on remote server sending ping. VyOS router in the middle. And internal host receiving pings.

  • Sending machine only shows echo requests. No replies.
  • VyOS shows both echo request and reply.
  • Internal host shows both echo request and reply.

So, the reply, I believe, is routing out over WG0, and is getting lost in the mix. Never makes it to the requesting host.

In PolicyBasedRoute rules, start with a rule matching internal server and internal source port, and use main table.
That way, reply is sent back on your normal WAN, not via VPN provider.