Forward SSH request to an External Server to an Internal Server [duplicate]

It would be very convenient, if all the clients could connect to port 22, and port forwarding could direct them to the proper server, depending on which hostname, the client wanted to access.

Unfortunately, that is just not possible.

The client never sends the hostname it is connecting to. (The only protocols I know of, where the client sends a hostname, which can be used for this sort of proxying are: http, https, smtp, dns). Moreover, the client will simply open a TCP connection and wait for a banner from the server. This means you will have absolutely no application layer information to base the choice of server on. Only once you have picked a server and gotten a banner from that server to send to the client, will the client start speaking ssh.

Faking the banner to the client from a proxy will not work either, because the proxy does not know exactly what the banner will look like, and if it got the banner wrong, the ssh client will notice this later during connection setup and report an integrity error.

You do have a few other options though.

Solution 1

Forward different port numbers from the gateway to port 22 on each server. For example:

-A PREROUTING -i eth0 -d 192.0.2.42 -p tcp --dport 62210 -j DNAT --to-destination 192.168.42.10:22
-A PREROUTING -i eth0 -d 192.0.2.42 -p tcp --dport 62211 -j DNAT --to-destination 192.168.42.11:22

Solution 2

Proxy SSH over another protocol. This could be done using HTTP CONNECT commands or by using SOCKS. On the ssh client, you can use ProxyCommand to specify a client speaking the relevant protocol with a proxy running on the gateway. The proxy software on the gateway then connects to the actual ssh server.

Solution 3

A variant of the proxy idea is to tunnel ssh over ssh. From the client you can run this command:

ssh -o ProxyCommand='ssh -W %h:%p bastion-host' [email protected]

bastion-host can be any of the hostnames assigned to your proxy. If authentication towards your proxy is publickey then authorized_keys can restrict what sort of access is granted. It should be possible to restrict access to just forward to the one relevant ssh port, and not allow the ssh connection to the proxy to be used for anything else.

Solution 4

Use IPv6. Then you can get enough IP addresses to have one for each of the servers. In case the ssh client is running on a network where the only way to get IPv6 access is by using Teredo, you can ensure that the ssh connectivity still works reliable by running a Teredo relay on the proxy. It takes less than five minutes to install Miredo and configure it to operate as a Teredo relay.


Just use SSH port-forwarding, it will be more secure (since you are not opening additional systems to the Net). E.g. you have host A with both public and private IP addresses, then you have hosts B and C sitting on the private network. To connect to B, use the following technique:

terminal-1$ ssh -L 10022:B_private_IP:22 A_public_IP

terminal-2$ ssh -p10022 user_at_B@0

as long as terminal-1 window is running you have an ssh tunnel to host B.

You can automate the whole thing using ~/.ssh/config, so you will be able to just do something like "ssh user_at_B@B" and it will fire up the tunnel for you.