WireGuard over reverse SSH tunnel

Hello,

I've recently moved to a new place where static IP address is not an option. I'm hosting a few websites and I was able to solve this by renting a VPS with static IP and setting a reverse SSH connection to it from my OpenWRT router. It works well.

Before moving, I also had WireGuard configured to be able to connect to my home network when traveling. I was hoping to solve it in a similar way, but in this case it's not working.

/etc/config/sshtunnel

config server 'vps'
	option user 'root'
	option hostname '***.***.***.***'
	option port '22'
	option retrydelay '1'
	option LogLevel 'DEBUG1'

config tunnelR 'http'
	option server 'vps'
	option remoteaddress '*'
	option remoteport '80'
	option localport '80'
	option localaddress '192.168.4.12'

config tunnelR 'https'
	option server 'vps'
	option remoteaddress '*'
	option remoteport '443'
	option localport '443'
	option localaddress '192.168.4.12'

config tunnelR 'wg'
	option server 'vps'
	option remoteaddress '*'
	option remoteport '51820'
	option localport '51820'
	option localaddress '192.168.9.1'

part of /etc/config/network

config interface 'vpn'
	option proto 'wireguard'
	option private_key '**************'
	option listen_port '51820'
	list addresses '192.168.9.1/24'

In the client's (mobile phone) WireGuard configuration, I just switched the IP address to the VPS one.

I feel like the reason it's not working is beyond my networking knowledge so here I am. Any help is greatly appreciated!

Delete this completely:

and this line too:

Worth to check your WG peer config as well.

I do not see a need to combine sshtunnel and WG in any way though, they should work completely independent. You definitely should not run "WireGuard over reverse SSH tunnel" as topic title says.

If you want your router to be accessible through WG, that can be achieved through VPS in a simple way:
Client-A <--> VPS <--> Client-B
where A is your OpenWrt router and B is your phone, or vice versa.

There is no client/server concept in WG, all the members are considered peers. In your setup you have only one member that can accept incoming connections from Internet, that is your VPS, so you can think of it as a server.

3 Likes

If both sides have a dynamic IP then a dyndns record together with the Wireguard watchdog could be an option too, to avoid the need of a VM/VPS.

1 Like

Good point. However, quite often people say "no static IP address" when in reality it should be "no public IP address". So I afraid this is what we have here. Just a guess.

1 Like

You're right. The address is static, but it's not public.

How does the mobile phone peer connect to the router? There would still need to be some traffic forwarding via the VPS, wouldn't it?

Let's use the term peer only in relation to WG network. Both router and phone have VPS as their peer, but they are not peers to each other.
Once both "clients" are connected to a "server" they appear on the same IP subnet (like 192.168.9.0/24) and should be able to talk to each other.
If everything is configured properly, you should be able to ping between all 3 addresses on WG subnet - two clients and a server.

I have this running, the router and vps can be set up as a site to site setup.

My phone is a "regular" peer.

Got it, I'll give it a go. Thanks a lot for pointing me in the right direction.

Thank you, I'll check it out!

The more conventional approach is to have both the home router and the mobile phone initiate Wireguard links to the VPS. Then the VPS forwards packets that are inside the tunnels. This can be done by having the phone and home as two peers of the same Wireguard interface on the VPS. Or you could use entirely separate tunnels.

Your SSH link forwards the outside packets, so referencing a 192.168.9 IP which is inside the tunnel is clearly wrong. If you continue to use ssh to forward to the house it needs to forward the outside port 51820 to the device that is running Wireguard at home.

Hello,

so I've spent the last few days trying to make it work. It's been quite challenging. I feel I'm close to get to the desired state but not quite there yet. If you could help me get over the finish line, I'd be eternally grateful.

I've been able to somewhat configure VPS.

/etc/wireguard/wg0.conf

[Interface]
PrivateKey = ***
Address = 192.168.9.20/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE

# openwrt
[Peer]
PublicKey = ***
AllowedIPs = 192.168.9.0/24

# mobile phone
[Peer]
PublicKey = ***
AllowedIPs = 192.168.9.3/32

The goal of the VPS is to forward incoming traffic from the mobile phone to the openwrt. I think I've been able to achieve that, because I can ping 192.168.9.10 (openwrt) from the mobile phone (although I had to ping from the openwrt first before it started working the other way, not sure why).

Openwrt wg configuration is the following:

/etc/config/network

config interface 'vpn_client'
	option proto 'wireguard'
	option private_key '***'
	list addresses '192.168.9.10/24'
	option postup '/etc/wireguard/postup.sh'
	option postdown '/etc/wireguard/postdown.sh'
#	option DNS '8.8.8.8'  // I was testing this option, no effect
	option auto '0'

config wireguard_vpn_client 'wgserver'
	option endpoint_host '***'
	option endpoint_port '51820'
	option persistent_keepalive '25'
	option route_allowed_ips '1'
	option description 'vps'
	option public_key '***'
	list allowed_ips '192.168.9.20/32'
	list allowed_ips '192.168.9.3/32'

/etc/wireguard/postup.sh

#!/bin/sh
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

/etc/wireguard/postdown.sh

#!/bin/sh
iptables -D FORWARD -i wg0 -j ACCEPT
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

To include the whole setup, here's also mobile phone's configuration:

I've also tried playing with firewall rules, dns, ip route rules, etc. Generally, what's missing in this setup? The goal is to access internet via openwrt (I have adguard home there so it'd be nice to use it when traveling) and also lan services.

On the server with multiple peers on one Wireguard interface, the assignments of those peers' allowed_ips must be non-overlapping. This generally means use the peer's tunnel IP /32 as an allowed IP, and if the peer is a router, allow any of the peer's LANs that should be reachable on the VPN.

I'm not sure I understand. The mobile phone peer is /32 as it's a single IP. OpenWrt peer is /24 because I want to forward there traffic from any IP address in the /24 range. I'm planning to have more peers like the mobile phone.

An allowed IP is an IP that exists at the other end of the link, and will be the source of packets coming into this machine or the destination of packets leaving this machine. Everything that the home router sends on the .9 network will come from its single IP 192.168.9.2. It may also forward traffic from home LAN devices so that subnet should be included as well.

This is the case I'm covering by having /24 on the openwrt peer.

From the VPS perspective, any packet it sends into that particular tunnel to the home router will have a destination of either 192.168.9.2, or an IP on the home LAN. If the packet's destination is 192.168.9.3, it needs to be sent to the iPhone instead, encrypted with the iPhone's key and sent to the iPhone's public IP.

The configuration of a non-overlapping set of allowed_ips is how the Wireguard kernel process makes this decision. This is probably the most complicated thing to understand about Wireguard.

At the home router packets may have originated from either the iPhone or the VPS itself, so it should be configured with at least a /24 to allow any 192.168.9.0. It's common to use 0.0.0.0/0 on these non-server peers that always link to exactly one other peer. That peer being the server. The iPhone isn't a Wireguard peer of the home router, it is reached indirectly through the server. There is no problem with overlap of allowed_ips at the end peers since only one tunnel is ever used, and the server will route inter-peer packets centrally.

1 Like

Okay, it's making more sense. I've updated home router AllowedIPs to 192.168.9.0/24. On the VPS, I've updated AllowedIPs to 192.168.9.10/32. There's no more overlap on the VPS peers. Hopefully that's what you meant.

One thing that's not clear to me. I've tried to ping home router (192.168.9.10) from the mobile phone (192.168.9.3) and it worked which I didn't expect since the VPS, according to AllowedIPs of home router, shouldn't forward that packet.

The phone generated a ping packet from 192.168.9.3 to 192.168.9.10. This packet went through the tunnel to the VPS, where it was decrypted and considered valid for reception since its source IP is 192.168.9.3, which is an allowed_ip for the phone peer.

The packet is forwarded out of the wireguard driver to the general Linux kernel. The VPS kernel then examines this packet and matches its destination IP (192.168.9.10) to the kernel routing table entry of 192.168.9.0/24 via wg0. It's important to note that this route entry was created by specifying a /24 as the wireguard interface IP, the same as would happen if you configure an IP onto an ordinary Ethernet interface. It's separate from Wireguard's internal allowed_ip table.

So the kernel sends the packet back into Wireguard. Wireguard matches the destination IP 192.168.9.10 as an allowed_ip of the home router, so the packet is re-encrypted this time with the home router key, and sent down that tunnel.

The home router receives the ping and dispatches a reply from 192.168.9.10 to 192.168.9.3, and the above process is repeated exactly in reverse. Ultimately the phone receives this reply packet and reports a successful ping.

2 Likes

It makes perfect sense, thank you. I'm glad I've got this part understood and configured properly. What's left is to route the traffic correctly on the home router.

Few additional questions, if I may.

  1. Is the traffic to the internet from the mobile phone really forwarded to openwrt? If I understand correctly, this rule iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE on the VPS forwards incoming traffic back to WG interface, but how does it know it should be forwarded to openwrt (192.168.9.10)? I've tried traceroute from the mobile phone and it ended up on the VPS (192.168.9.20). What if there were more peers? Current version of VPS WG config:
[Interface]
PrivateKey = ***
Address = 192.168.9.20/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE

# openwrt
[Peer]
PublicKey = ***
AllowedIPs = 192.168.9.10/32

# mobile phone
[Peer]
PublicKey = ***
AllowedIPs = 192.168.9.3/32

I'm thinking there might be a need for some ip route rule outside of the WG config?

  1. Does setting DNS on the mobile phone WG interface to 192.168.9.10 have any effect? In case the forwarding it set correctly, all packets (including DNS requests) should go to openwrt anyway, is the assumption correct?

  2. What are the steps I should take on openwrt to allow mobile phone to access local services on openwrt LAN and also the internet via openwrt?

I looked through my notes and this is what I could find maybe this gives you some idea how to proceed:
Regarding the firewall routes on the VPS, these are what I am using:

The PostUp:

#!/bin/bash
IPT="/sbin/iptables"
IPT6="/sbin/ip6tables"

IN_FACE="ens3"                   # NIC connected to the internet
WG_FACE="wg0"                    # WG NIC
SUB_NET="10.168.0.0/24"          # WG IPv4 sub/net aka CIDR
WG_PORT="51801"                  # WG udp port
SUB_NET_6="fd42:42:42::/64"      # WG IPv6 sub/net

## IPv4 ##
$IPT -t nat -I POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
$IPT -I INPUT -i $WG_FACE -j ACCEPT
$IPT -I FORWARD  -i $WG_FACE  -j ACCEPT
$IPT -I INPUT -i $IN_FACE -p udp --dport $WG_PORT -j ACCEPT

$IPT6 -t nat -I POSTROUTINGreboot -s $SUB_NET_6 -o $IN_FACE -j MASQUERADE
$IPT6 -I INPUT -i $WG_FACE -j ACCEPT
$IPT6 -I INPUT -i $IN_FACE -p udp --dport $WG_PORT -j ACCEPT
$IPT6 -I FORWARD -i $WG_FACE  -j ACCEPT

PostDown:

#!/bin/bash
IPT="/sbin/iptables"
IPT6="/sbin/ip6tables"

IN_FACE="ens3"                   # NIC connected to the internet
WG_FACE="wg0"                    # WG NIC
SUB_NET="10.168.0.0/24"          # WG IPv4 sub/net aka CIDR
WG_PORT="51801"                  # WG udp port
SUB_NET_6="fd42:42:42::/64"      # WG IPv6 sub/net

# IPv4 rules #
$IPT -t nat -D POSTROUTING -s $SUB_NET -o $IN_FACE -j MASQUERADE
$IPT -D INPUT -i $WG_FACE -j ACCEPT
$IPT -D FORWARD -i $WG_FACE -j ACCEPT
$IPT -D INPUT -i $IN_FACE -p udp --dport $WG_PORT -j ACCEPT

# IPv6 rules (uncomment) #
$IPT6 -t nat -D POSTROUTING -s $SUB_NET_6 -o $IN_FACE -j MASQUERADE
$IPT6 -D INPUT -i $WG_FACE -j ACCEPT
$IPT6 -D FORWARD -i $IN_FACE -o $WG_FACE -j ACCEPT
$IPT6 -D FORWARD -i $WG_FACE -o $IN_FACE -j ACCEPT

Furthermore on the VPS I have in the Allowed IPs for the OpenWRT router not only the WG address but also the lans subnet, necessary as I do not Masquerade on the OpenWRT router.

You are correct that all traffic form the peers are going out of the VPS, you however want your mobile phone to go to your OWRT router.

I do this with the following two rules:

ip route add default via 10.168.0.2 table 10  #ip address of the site-to-site setup
ip rule add from 10.168.0.3/32 table 10

10.168.0.2/32 is the WG address of the OWRT router
10.168.0.3/32 is the WG address of my mobile phone