HTTP server through reverse ssh tunneling

I have linux-based device (let's say a Raspberry Pi) that hosts a HTTP server. This device regularly changes WiFi access point and is often not publicly accessible due to NAT and/or firewall.

I want to setup a reverse ssh tunnel using a publicly available server (rpi.example.com below) such that rpi behind NAT establish a tunnel to rpi.example.com at boot. rpi.example.com will then forward any HTTP request to the rpi behind NAT.

Sequence diagram:

HTTP client       rpi.example.com     rpi behind NAT
     +                   +                   +
     |                   |       ssh -R      |
     |                   | <-----------------+
     |    GET /temp      |                   |
     +-----------------> |                   |
     |                   +-----------------> |
     |                   |   [SSH tunnel]    |
     |                   | <-----------------|
     |  HTTP/1.1 200 OK  |                   |
     | <-----------------+                   |
     |                   |                   |

How to setup a reverse SSH tunnel like that? Is there a better alternative?


I think a VPN (e.g. openVPN or an IPSEC solution like strongswan) might work better.

You can absolutely use SSH, with the -R switch:

-R remote_socket:local_socket

Specifies that connections to the given TCP port or Unix socket on the remote (server) host are to be forwarded to the given host and port, or Unix socket, on the local side. This works by allocating a socket to listen to either a TCP port or to a Unix socket on the remote side. Whenever a connection is made to this port or Unix socket, the connection is forwarded over the secure channel, and a connection is made to either host port hostport, or local_socket, from the local machine.

You would just need something on your Pi to initiate the connection, and re-start it if it fails. The NAT here is irrelevant, because the tunnel would be directly between your public host and Pi - on your host, you would in effect have a listener (e.g. 127.0.0.1:9999), and would configure your webserver to use that listener as an upstream.

Most likely, you would want to have a dedicated user to create this forwarding (since your Pi would need to be able to authenticate to your server, which almost certainly means you would need a passwordless private key). You would also need to create one forwarded connection per port, if you ever needed more than one.

I suspect a VPN would be easier to make work reliably, and would require less scripting, essentially. Both approaches would work, though.