SSH port forwarding from VPS to home server

January 6th, 2011 | by Sean |

Spider.my is served by a very small VPS provided by Nocser. The search function of spider.my is currently served by 2 reasonably-sized Xeon servers near my desk. I can’t currently afford to rent the equivalent amount of computing power from a hosting company, so the front-end of spider.my is all served by the VPS, with search results and indexing all done at home. I did have a horrible cross-domain javascript hack which caused a user’s browser to fetch the search results from my servers at home, but it was a horrible kludge and according to the server logs didn’t seem to work on all browsers.

I briefly considered writing some sort of proxy code for the webserver on the VPS, but this also seemed a kludge. The backend of spider.my is implemented as separate RMI services. One obvious solution would be to open up the RMI service ports on my router at home and use Dynamic DNS to keep a domain name resolving to whatever my home IP address is, and make RMI requests from code running on the VPS. This also seemed unnecessarily complicated and an obvious security risk.

What I plumped for in the end is SSH port forwarding – connecting my backend service with the frontend on the VPS over a secure socket. The SSH connection is established by the backend so there’s no need for Dynamic DNS. An SSH connection is setup by an unprivileged account on the backend server which opens sockets on the frontend server. Connections made by applications running on the frontend server are then forwarded to corresponding ports on the backend server.

Here’s the command I use on my backend server to show use of the -R argument:

ssh -R 1099:localhost:1099 -R 1100:localhost:1100 -R 1101:localhost:1101 nopriv@frontend.box -N

Any connections to 1099 on the frontend server are forward to port 1099 (the default rmiregistry port) on the backend server. I have two RMI services running on the backend server, on ports 1100 and 1101. The frontend code can connect to the rmiregistry as though it was running on localhost, but all communication is forwarded over the SSH connection. It works a treat!

I came up against just 2 or 3 ‘wrinkles’. The first was host naming – I ended up making an entry in the frontend’s /etc/hosts to map the backend server’s hostname (for rmiregistry discovery) onto 127.0.0.1 – that allows me to use the application unmodified. To enable the connection to be established without typing a password, ssh-keygen has to be used exactly as stated in ssh’s manpages. Last, I had a problem with the SSH session dying, possibly due to lack of activity as in this article. I used the ‘-o ServerAliveInterval=’ command line option and that seemed to make it rock-solid. I’m also using ‘-c blowfish’ just because the manpages say “it appears very secure and is much faster than [the default]”.

Post a Comment