Using a reverse SSH tunnel to provide an isolated system such as a Raspberry Pi with network access (well, HTTP)

Imagine you have a system to which you can only SSH inbound but which is unable to reach any host on the Internet outside the local network. For instance, you might have tightened down network access to secure a local CA. Or, like me, you have a Raspberry Pi that you carried around with you on a trip, so on the one hand you could only access it via network — or do you carry a HDMI display around with you? So you set its Wifi up as an access point spawning its own Wifi network, which, on the other hand, cut it off from Internet access, unless you can configure multiple interfaces. But then, still, network connectivity changes as you travel, from LAN to Wifi to LTE perhaps.

One simple answer to this problem is to reuse the laptop you’re using to SSH to the Pi for network connectivity. To this extent, we use ssh’s -R option which opens a reverse tunnel, meaning a listening TCP port on the target machine, the Pi, is forwarded to a local port, with a syntax similar to the following:

ssh -R 8888:127.0.0.1:8888 pi@192.168.99.1

Next we need to tell applications on the Pi about our proxy. For the probably most common usage pattern, updating the system, we can create /etc/apt/apt.conf.d/99proxy as follows:

Acquire::http::proxy “http://localhost:8888”;

Update 2024-03-06: As Florian Hennig adds, you can of course also simply use environment variables to only temporarily redirect apt-get to the proxy: sudo http_proxy=http://localhost:8888 apt-update.

So far we have a TCP pipe ending on our laptop on port 8888 but there is nothing there yet to handle the traffic. We could, of course, install Squid but that’s a bit like taking a sledgehammer to crack a nut. Instead this is where Tinyproxy enters the stage, “designed from the ground up to be fast and yet small”. It is also very easy to configure with the most important options in /etc/tinyproxy.conf being:

Port 8888
Listen 127.0.0.1

but, as always, check twice that the port you choose is not accessible to the outside world.

Done! Now you can happily apt update all the way along. Note that using SSH as a SOCKS proxy (i.e. by omitting the local port to the -R option above) won’t work as easily while you can configure e.g. apt also to use a SOCKS proxy, the Pi would still try to resolve DNS hostnames itself, so you’d also have to tunnel DNS.