Connecting to a server's web interface with SSH

Sometimes, we have to remotely administer servers. And sometimes, those servers run a daemon that has to be configured using a web interface - e.g. CUPS or ejabberd.

In order to connect to such a web interface, you need a browser, an IP address and a port. In essence, the web interface has to be publicly accessible for that - which is not something you'd usually want. (Firewall configuration, access control, security risks, possibly needing port forwarding, and so on.)

Now there are many ways to remotely administer servers using a GUI. All of which have one thing in common: they suck. Either they're free software and they suck (VNC, X forwarding, …) or they're proprietary and they suck even more (RDP, NX, TeamViewer, …) And then there's the whole issue of how it's outright ridiculous to install a GUI on a server in the first place.

Fortunately, one can easily bind a server's local port to a client's local port using nothing but SSH. This means you only need to use port 22, and you can use SSH pubkey authentication and encryption for everything you do.

All it takes is this command:

ssh [username]@[hostname] -T -L [random-local-port]:localhost:[desired-server-port]

For example, what if you wanted to access the CUPS admin page as user olimex on your OLinuXino, with hostname lithium and IP 192.168.0.2, without having to allow TCP traffic on port 631?

The username would be olimex
The hostname would be lithium.local (or 192.168.0.2)
The random local port can be anything, so let's use 63789
The server port would be 631

That would mean: ssh olimex@lithium.local -T -L 63789:localhost:631

Enter the password (if you don't have pubkey access), press Enter, open localhost:63789 on the client, and enjoy.

Killing a tunnel is also easy: just hit Ctrl + D and close the terminal.

So what if you want to connect to the web interface of a daemon running on another server in the same LAN as the server you have SSH access to, while the server in question is not remotely accessible? Even that is possible!

Say, for example, your server is in a LAN and has 192.168.0.50 as its internal IP address. 192.168.0.50:22 will be forwarded to a random port of the external IP address (let's say 90.70.60.50:4444). You have a local user account called cindy.

Another server in the LAN has 192.168.0.60 as its internal IP address, has chatserver as its hostname, and let's say it runs the ejabberd web interface on the default port 5280.

You can once again use the familiar command:

ssh [username]@[external-ip] -p [external-port] -T -L [random-local-port]:[desired-server-in-the-lan]:[desired-server-port]

The username would be cindy
The external IP would be 90.70.60.50
The external port would be 4444
The random local port can be anything, so let's use 5599
The other server in the LAN would be chatserver.local (or 192.168.0.60)
The other server's port would be 5280

That would mean: ssh cindy@90.70.60.50 -p 4444 -T -L 5599:192.168.0.60:5280

Sometimes, you can't get by with mapping only a single port. (Think about SSL redirects, for instance.) In that case, you can use SSH to set up a SOCKS host and tell your browser to connect through that as a proxy.

Let's say that you want to access multiple things in the LAN of a remote machine you have access to.

You can set up a tunnel by using this command:

ssh -N -D [random-local-port] [username]@[external-ip] -p [external-port]

Let's use the same variables as before:

The username would be cindy The external IP would be 90.70.60.50 The external port would be 4444 The random local port can be anything, so let's use 5599

That would mean: ssh -N -D 5599 cindy@90.70.60.50 -p 4444

You can then tell your browser to use the SOCKS host on localhost:5599.

With Firefox, you go to Preferences –> Advanced –> Network –> Settings –> Manual proxy configuration.

With Chromium, the system proxy settings are inherited. So you'll have to set up Network Manager and apply the proxy system-wide.

Don't forget to undo the settings once you're done!

Sometimes, the local admin is mean and refuses to forward a port. In that case, you won't be able to connect to any SSH server behind NAT. But fear not! SSH can still help you if the local admin cannot.

However, you're going to need some infrastructure on your side. At least a publicly accessible server running SSH and preferably nothing else. Sure, if you have a static IP or something like DynDNS you could use your own computer at home, but we really don't recommend it.

In the best case scenario, you rent a very basic VPS somewhere, and do a minimal GNU/Linux server install on it. Install openssh-server and perhaps a firewall that blocks all traffic except port 22. Create a user account on that VPS with as little rights as possible. (Just its own home directory, and keep it out of the sudoers file.)

In this example, let's say that you have a VPS somewhere with the IP address 88.55.22.90, and that you bought a domain name for it: datraverse.eu.

You made a user account called adminsaremean.

Anyone can connect to this server if they'd guess the password (so choose a strong one). But there's nothing interesting on the server, and the user account can't do anything interesting either. However, it can be very valuable as a reverse SSH proxy server.

So how does one use a reverse SSH proxy server? Well, from the client side (the machine that wasn't allowed to have its port forwarded), you connect to the publicly accessible proxy server on a random port. Let's say the client's user account is called hippopotamus. Then, you connect to the server from your computer. From that shell, you connect to localhost with the random port you chose.

First things first: connecting to your proxy from the client you want remote access to. You'll need to do this:

ssh -N -R [random-port]:localhost:22 [username]@[proxy-server]

The random port can be anything, so let's use 1234
The username will be adminsaremean
The proxy server will be datraverse.eu

That would mean:

hippopotamus@client-somewhere-far-away:~$
ssh -N -R 1234:localhost:22 adminsaremean@datraverse.eu

Running this command will show nothing interesting. That's exactly what we want. Of course, you can also script this for easy initiation. Or add it to /etc/rc.local. (But beware that you'll probably want pubkey authentication for that.)

Now, on to the server. The remote client, with user account hippopotamus, will be connected to port 1234, and you want to open a secure shell from your server to that client. This can be done with the following command (from the proxy server):

ssh [username]@localhost -p [random-port]

The username will be hippopotamus
The random port will be 1234

That would mean:

adminsaremean@proxy-server:~$
ssh hippopotamus@localhost -p 1234

Now you'll be logged in to the remote client, even though it's behind NAT and maybe even a firewall, no matter how mean the local admin is.

Connecting to a web interface this way, is really hard. You'll need to create two tunnels: one from the client to the server, and one from your computer to the server. So, we're still connected from the client to port 1234 on the server. And we want, for instance, access to the CUPS admin page on the client.

In order to do so, you'll first need a tunnel from port 631 on the client to a random port on the proxy server. Let's use 5678 in this example:

adminsaremean@proxy-server:~$
ssh hippopotamus@localhost -p 1234 -T -L 5678:localhost:631

If you're hardcore, you can now use lynx or w3m to connect to localhost:5678 on your proxy server. But that's not ideal, of course.

So from your computer, you connect to the proxy server and bind port 5678 (which is forwarded to 631 on the client) to another random local port. Let's use 6070 in this example:

cindy@thinkpad-with-coreboot:~$
ssh adminsaremean@theunconventional.xxx -T -L 6070:localhost:5678

This would mean that port 6070 on your computer is forwarded to port 5678 on the proxy server, which in turn is forwarded to port 631 on localhost:1234 on the proxy server, which is actually port 22 on the remote client, meaning that the localhost:631 on the proxy server actually wasn't the local host! Think about this right before you go to bed!

I have the remote client set up to only accept the public key on my laptop. Will this still work securely?

Because you're using reverse SSH to connect to the server, this connection will be outgoing rather than incoming from the remote client's end. However, it will treat any connection to the random port on the proxy server as an incoming SSH connection. So you will have to create a public key on the server with a very strong passphrase, and add it to ~/.ssh/authorized_keys on the remote client.

I don't want my proxy server to allow password authentication. Will that work?

Sure. But you'll need to create SSH keys for every remote client you ever want to manage and every computer you ever want to use to remotely manage those clients, and add those pubkeys to ~/.ssh/authorized_keys on your proxy server.

But if I use pubkey authentication, any clever user on the client side could log in to any other client, which may not even be theirs!

First off, there is no such thing as a clever user. ;)
Jokes aside: they'd still need your pubkey password, and you should of course never cache that on the proxy server.

But if this really bothers you, you can also create a separate user account on the proxy server with each their own SSH keys and authorized_keys files. They won't have access to eachother's home directories, but you will have a lot of work storing all those passwords and adding all those keys.

  • howto/ssh.txt
  • Last modified: 2019/11/10 19:03
  • by admin