Port forward to a target device from VPS Wireguard (over VPN tunnel)

Hello,

I have VPS server and OpenWRT router behind CGNAT. I want to forward port so when I enter 33.129.202.22 it should forward request to 192.168.1.1 which then will forward traffic to 192.168.1.5. Here is diagram:

I want to achieve easiest solution, without using PBR. From server side, everything is working (I have second device, Mikrotik that works exactly on same VPS but different ports).

So my question is not about setting up VPS, I just want to know how to handle it on OpenWRT.

Wireguard client also works on OpenWRT. I can ping server -> openwrt and openwrt -> server, but port forwarding just not works.

I think response does not know where to go. I don't want to tunnel all outgoing traffic (If I will check checkbox route all traffic and allowed ips = 0.0.0.0/0 everything works, even port forwarding).

Any ideas?

Thanks in advance!

1 Like

Let me share my experience. I have two routers deployed. I am downstream of the wireguard router which is a MikroTik RouterBOARD 951Ui-2nD running LuCI openwrt-19.07.

The 'Tic OpenWRT is checked to route all traffic via wg. Connected to it is a lowly Grandstream ATA . For several weeks I attempted to get the device configured (ATA) to connect outside the tunnel with no success. DMZ/Port Fwd nothing allowed the ATA to grab 5060-5061 5079-5080 UPD to get the provisioning. Wireguard is doing it job. Somewhat throwing in the towel I put the ATA on a third router upstream the 'Tik. Since it was no longer encumbered by the tunnel enforced by Wireguard ~ it provisioned.

However, I didn't like having another router in the house with the sole purpose of providing me Voip. I left it like that while I scoured the internet for something that would bring my back to two router and that was PBR/VPR
[vpn-policy-routing 0.2.1-13].

With this regard, I'm not attempting to dissuade you to look for the simplest solution without using PBR. I'm sharing. A third router for you, outside the wg tunnel might be an option to consider if you have not already.

If you have requisite skill in RouterOS we have a community member that could use your help @sevo, and perhaps you two can assist each other achieving goals.
Warm Regards
Bill

The Edit:
Thank you @midler for a thought provoking question:
Thank you @pavelgl for providing me a solution via PM to the ATA
vpn policy base routing is stopped/disabled

The Fix for ATA ~ Voip ~

config interface 'wan'
	option ifname 'eth0'
	option proto 'dhcp'
	option peerdns '0'
	list dns '127.0.0.1'
	option metric '10'     # Added Metric option 

config rule                        # confg rule where option src 'ATA Device'
	option in 'lan'
	option src '192.168.33.xxx/32'
	option lookup '100'

config route                      # option gateway 'ISP gateway'
	option target '0.0.0.0/0'
	option interface 'wan'
	option table '100'
	option gateway 'xxx.254.44.1'

/etc/config$ ip route show default
default dev SSWG proto static scope link 
default via xxx.254.44.1 dev eth0 proto static src xxx.254.44.175 metric 10 
/etc/config$ ip rule
0:	from all lookup local 
1:	from 192.168.33.xxx iif br-lan lookup 100 
32766:	from all lookup main 
32767:	from all lookup default 
/etc/config$ ip route show table 100
default via xxx.254.44.1 dev eth0 proto static metric 10

@midler
If your problem is solved, please consider marking this topic as [Solved]. This will help community members as well as visitor quickly find results. In this case possibly TWO! Happy Routing my friends. See How to mark a topic as [Solved] for a short how-to.

You can use SNAT to hide external requests behind the router's LAN IP address.

For testing purposes:

iptables -t nat -I zone_lan_postrouting -d 192.168.1.5/32 -j SNAT --to-source 192.168.1.1

If it works as expected:

uci add firewall nat
uci set firewall.@nat[-1].name='snat_to_camera'
uci set firewall.@nat[-1].proto='all'
uci set firewall.@nat[-1].src='lan'
uci set firewall.@nat[-1].target='SNAT'
uci set firewall.@nat[-1].snat_ip='192.168.1.1'
uci set firewall.@nat[-1].dest_ip='192.168.1.5'
2 Likes

It does not works.

Alright, it's my fault, I should give more information. Let's start from beginning to not lose time and help others understand how to fix this issue as there is no clear answer I can find.

So, here is my env: I have raspberry pi4 with OpenWRT for testing. I am getting internet from wifi. On lan, there is Ubuntu connected and port 80 opened (ip - 192.168.1.5). When I open ubuntu locally, simple html text is displayed saying "hey there". (instead of camera, let's say we want to enter "hey there" page using browser)

In OpenWRT, I have created new interface named "wireguard" and succesfully connected to VPS. Assigned to firewall zone "wan" I have NOT ticked "Route Allowed IPs" in wireguard interface. So now I can NOT ping 10.1.1.1 (wireguard server from OpenWRT) and I can NOT ping 10.1.1.3 (openwrt from VPS).

Here is OpenWRT config:

package dhcp

config dnsmasq
	option domainneeded '1'
	option boguspriv '1'
	option filterwin2k '0'
	option localise_queries '1'
	option rebind_protection '1'
	option rebind_localhost '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option nonegcache '0'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
	option nonwildcard '1'
	option localservice '1'
	option ednspacket_max '1232'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '12h'
	option dhcpv4 'server'
	option dhcpv6 'server'
	option ra 'server'
	option ra_slaac '1'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

package dropbear

config dropbear
	option PasswordAuth 'on'
	option RootPasswordAuth 'on'
	option Port '22'

package firewall

config defaults
	option syn_flood '1'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'

config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wan'
	list network 'wan6'
	list network 'wwan'
	list network 'wireguard'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option src_ip 'fc00::/6'
	option dest_ip 'fc00::/6'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config rule
	option name 'Support-UDP-Traceroute'
	option src 'wan'
	option dest_port '33434:33689'
	option proto 'udp'
	option family 'ipv4'
	option target 'REJECT'
	option enabled 'false'

config include
	option path '/etc/firewall.user'

package luci

config core 'main'
	option lang 'auto'
	option mediaurlbase '/luci-static/bootstrap'
	option resourcebase '/luci-static/resources'
	option ubuspath '/ubus/'

config extern 'flash_keep'
	option uci '/etc/config/'
	option dropbear '/etc/dropbear/'
	option openvpn '/etc/openvpn/'
	option passwd '/etc/passwd'
	option opkg '/etc/opkg.conf'
	option firewall '/etc/firewall.user'
	option uploads '/lib/uci/upload/'

config internal 'languages'

config internal 'sauth'
	option sessionpath '/tmp/luci-sessions'
	option sessiontime '3600'

config internal 'ccache'
	option enable '1'

config internal 'themes'
	option Bootstrap '/luci-static/bootstrap'

config internal 'apply'
	option rollback '90'
	option holdoff '4'
	option timeout '5'
	option display '1.5'

config internal 'diag'
	option dns 'openwrt.org'
	option ping 'openwrt.org'
	option route 'openwrt.org'

package network

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fd15:0da7:1c68::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth0'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'wwan'
	option proto 'dhcp'

config interface 'wireguard'
	option proto 'wireguard'
	option private_key 'MY_PRIVATE_KEY'
	list addresses '10.1.1.3'

config wireguard_wireguard
	option description 'Peer'
	option public_key 'MY_PUBLIC_KEY'
	list allowed_ips '0.0.0.0/0'
	list allowed_ips '::/0'
	option endpoint_host 'MY_ENDPOINT'
	option persistent_keepalive '20'

package rpcd

config rpcd
	option socket '/var/run/ubus/ubus.sock'
	option timeout '30'

config login
	option username 'root'
	option password '$p$root'
	list read '*'
	list write '*'

package system

config system
	option hostname 'OpenWrt'
	option timezone 'UTC'
	option ttylogin '0'
	option log_size '64'
	option urandom_seed '0'

config timeserver 'ntp'
	option enabled '1'
	option enable_server '0'
	list server '0.openwrt.pool.ntp.org'
	list server '1.openwrt.pool.ntp.org'
	list server '2.openwrt.pool.ntp.org'
	list server '3.openwrt.pool.ntp.org'

package ucitrack

config network
	option init 'network'
	list affects 'dhcp'

config wireless
	list affects 'network'

config firewall
	option init 'firewall'
	list affects 'luci-splash'
	list affects 'qos'
	list affects 'miniupnpd'

config olsr
	option init 'olsrd'

config dhcp
	option init 'dnsmasq'
	list affects 'odhcpd'

config odhcpd
	option init 'odhcpd'

config dropbear
	option init 'dropbear'

config httpd
	option init 'httpd'

config fstab
	option exec '/sbin/block mount'

config qos
	option init 'qos'

config system
	option init 'led'
	option exec '/etc/init.d/log reload'
	list affects 'luci_statistics'
	list affects 'dhcp'

config luci_splash
	option init 'luci_splash'

config upnpd
	option init 'miniupnpd'

config ntpclient
	option init 'ntpclient'

config samba
	option init 'samba'

config tinyproxy
	option init 'tinyproxy'

package uhttpd

config uhttpd 'main'
	list listen_http '0.0.0.0:80'
	list listen_http '[::]:80'
	list listen_https '0.0.0.0:443'
	list listen_https '[::]:443'
	option redirect_https '0'
	option home '/www'
	option rfc1918_filter '1'
	option max_requests '3'
	option max_connections '100'
	option cert '/etc/uhttpd.crt'
	option key '/etc/uhttpd.key'
	option cgi_prefix '/cgi-bin'
	list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
	option script_timeout '60'
	option network_timeout '30'
	option http_keepalive '20'
	option tcp_keepalive '1'
	option ubus_prefix '/ubus'

config cert 'defaults'
	option days '730'
	option key_type 'ec'
	option bits '2048'
	option ec_curve 'P-256'
	option country 'ZZ'
	option state 'Somewhere'
	option location 'Unknown'
	option commonname 'OpenWrt'

package wireless

config wifi-device 'radio0'
	option type 'mac80211'
	option channel '36'
	option hwmode '11a'
	option path 'platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:1'
	option htmode 'VHT80'
	option cell_density '0'

config wifi-iface 'wifinet0'
	option device 'radio0'
	option mode 'sta'
	option network 'wwan'
	option ssid 'myWiFi'
	option encryption 'psk2'
	option key 'myWiFiKey'

What's next?

wg show
ip route show default

Edit the sensitives

wg show:

interface: wireguard
  public key: MY_PUBLIC_KEY
  private key: (hidden)
  listening port: 59778

peer: MY_PEER_CODE
  endpoint: 33.129.202.22:51820
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 18 seconds ago
  transfer: 1.01 MiB received, 1.00 MiB sent
  persistent keepalive: every 20 seconds

ip route show default:

33.129.202.22 via 192.168.3.1 dev wlan0 
192.168.1.0/24 dev br-lan scope link  src 192.168.1.1 
192.168.3.0/24 dev wlan0 scope link  src 192.168.3.38

Got it where you want it now?

Just asking because the initial pre edit had wg up top as default. Since I know you have not ticked "Route Allowed IPs", and seeing the ISP address, how would you expect to ping VPS? Can you now?

I just want simple thing - router should function normally, as there is no VPN at all, clients will not notice that I have VPN configured. I just want to have VPN to port forward to local devices through tunnel, nothing more.

But when I configure port forwarding, it does not work.

Just asking because the initial pre edit had wg up top as default. Since I know you have not ticked "Route Allowed IPs", and seeing the ISP address, how would you expect to ping VPS? Can you now?

I have manually added static route (in pre edit, then for not making confusions, I removed this as in export this rule does not exists)

config route
	option interface 'wireguard'
	option netmask '0.0.0.0'
	option source '10.1.1.3'
	option target '10.1.1.0/24'
	option disabled '0'

With this, I can ping server and server pings client. But port forwarding does not work anyway.

I guess my fix was simpler than your, because I knew I wanted everything vpn tunneled via wg, and only had one device that need exposure.

But @pavelgl provided me a link, that you may have already read.

You want nothing but a vpn and a port fwd to see when you're in the cloud accessing your vpn correct?

EDIT
Thank You ~ gonna let your last comment percolate while I stew on CGNAT.

This is where we are and can't ping bidirectional (wg) as we are on ISP w/ working port fwd.

33.129.202.22 via 192.168.3.1 dev wlan0 
192.168.1.0/24 dev br-lan scope link  src 192.168.1.1 
192.168.3.0/24 dev wlan0 scope link  src 192.168.3.```

Yes, you are correct. As I can't port forward devices under CGNAT, I want to use VPN and access local devices with it from anywhere.

VPS

You need to enable SNAT or masquerading on the VPS itself to hide the incoming requests behind 10.1.1.1.
Example:

iptables -t nat -I POSTROUTING -d 10.1.1.3/32 -j SNAT --to-source 10.1.1.1
# or
iptables -t nat -I POSTROUTING -o $wg_interface -j MASQUERADE

I assume that you are forwarding the requests to 10.1.1.3.

OpenWrt

You should be able to ping the server without additional static routes.
Modify the peer interface:

config wireguard_wireguard
	    option description 'Peer'
	    option public_key 'MY_PUBLIC_KEY'
	    list allowed_ips '10.1.1.1/32'
	    option endpoint_host 'MY_ENDPOINT'
	    option persistent_keepalive '20'
	    option route_allowed_ips '1'

And just to be sure, the redirect (test) rule should look like this:

config redirect
        option dest_port '80'
        option src 'wan'
        option name 'HTTP'
        option src_dport '80'
        option target 'DNAT'
        option dest 'lan'
        list proto 'tcp'
        option dest_ip '192.168.1.5'

I have modified peer as you suggested. Ping works on both sides, but port forwarding don't. Here is my VPS configuration:

-A POSTROUTING -s 10.1.1.0/24 -o eth0 -j MASQUERADE

-A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.1.1.3:80
-A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 10.1.1.3:443

Isn't this same you wrote me about VPS? This configuration on VPS works on OpenWRT if I will tick "route all traffic" and allowed ip = 0.0.0.0/0 (after this your redirect rule works)

Is eth0 the name of the wireguard interface?
Check all available interfaces using ip link
Use -I instead of -A to insert the rule at the beginning of the chain.
And please try this rule on the VPS

iptables -t nat -I POSTROUTING -d 10.1.1.3/32 -j SNAT --to-source 10.1.1.1

EDIT:
Also remove -s 10.1.1.0/24. Use only the outgoing (wireguard) interface.

1 Like

THANK YOU!

On VPS, I have

-I POSTROUTING -o wg0 -j MASQUERADE
-I PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 10.1.1.3:80

And everything is perfectly working!

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.