Here i’ll explain how to setup a reverse SSH proxy on Ubuntu so you can route calls from the internet to your local development.

If you build software at some point you’ll get into a situation when you need to develop against a webservice or webhooks. Since you’re developing local, the changes are that the webhooks can’t access your development environment to post the data.

A handy option to fix this is using a SSH reverse proxy. This allows the webhooks or APIs to post their data to a url which is accessible from the internet. This will then in turn be routed to your local environment. Pretty neat!

Localtunnel is a service which does this for you, but unfortunately, this hasn’t been up for a long time. But luckily, i’ts not so hard to roll your own, so lets do that.

A word of warning

SSH can be quite complicated stuf, and traffic forwarding and opening ports etc. Can be considered bad by some people. Also changing IP tables can severly mess up your server if you don’t know what you’re doing.

My usecase

I needed this when I was developing the buckaroo-gem. My payment provider sends API/webhooks calls regarding the status of my payments to an external URL. It was quite demanding little bugger of an API cause it also only wanted it send its callbacks to port 80. So I needed to come up with some clever trick to build my integration tests.

Prerequisites

In order to do this you need to do a couple of things:

  • Be in possession of your own server which is publicly accessible on the internet
  • Change your SSH settings on your server
  • Setup routing of port 80 if you want to route trough port 80.

Setting up SSH for to allow TCP forwards (Ubuntu)

Go login on your internet accessible REMOTE SSH server. And change some settings there. To do this go to /etc/config/.sshd-config, and add or change the following lines:

GatewayPorts clientspecified
AllowTcpForwarding yes

Then go and reload your ssh using service ssh reload.

After this you can forward your ssh using this magic. Use this fairly intimidating line to reverse proxy the data:

ssh -R *:3000:127.0.0.1:3000 <ssh-user>@<ssh-host> -N

Which means: <remote-interface>:<remote-port>:<to-host>:<to-port> <ssh-user>:<ssh-host> The -R means reverse. And the -L means bind address.

After you hit enter you’d see…. NOTHING. It should just be blocking. If you then navigate to your external IP and try to access and it will route trough your localhost.

Binding to port 80

By default you can’t bind to anything lower than port 1000 unless you’re some kind of sudo uberbeing. So if you want to reroute port 80 you need to create an IP table redirect.

First go and allow to accept 80 and 8080.

iptables -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 8080 -j ACCEPT

Then finally add some prerouting magic:

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

Which will route all traffic from port 80 to 8080.

Then you can just easiy connect reverse your ssh to this port like this:

ssh -R *:8080:127.0.0.1:3000 <ssh-user>@<ssh-host> -N

You should then be able to browse to your local server from your remote ip without specifying a port. ACE!

If you want to delete your iproute and gain access back over your port 80. You can just drop the prerouting like this.

First check get the prerouted tables with the NAT.

iptables -L -t nat --line-numbers

Then delete the route:

iptables -t nat -D PREROUTING <linenumber>

A final word

It’s ofcourse a bit sad that now port 80 is unusable. Because it’s routed to your localhost. A better way would be use a proxy that only forwards it to the right host when for instance a subdomain is used.

Similar to the way localtunnel works.

Hey you 👋. Want to stay up to date?

Would you like to stay up to date on upcoming learn-togethers or events? Subscribe here! I'll only use your email to keep u up to date on new learnings and coding tips. It wont be shared! Feel free to unsubscribe anytime!