Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

I've grown quite fond of HTTP reverse proxies in our development environment and found the DNS based virtual host reverse proxy quite useful. Having only one port (and the standard one) open on the firewall makes it much easier for management.

I'd like to find something similar to do SSH connections but haven't had much luck. I'd prefer not to simply use SSH tunneling since that requires opening port ranges other than the standard. Is there anything out there that can do this?

Could HAProxy do this?

share|improve this question
Is your intended application file transfer, or actual SSH access to hosts? –  Kyle Hodgson Jul 1 '09 at 16:20
Direct SSH access to the host is the goal. This need comes from the desire to run a Mercurial server in-house but our server is behind the firewall. Right now I'm working on simply setting up an HTTP version but I wanted to have commits use SSH instead of HTTP. Direct SSH access to other servers would be a bonus if this was possible. –  ahanson Jul 1 '09 at 19:01
This is such an annoying problem. –  bias Dec 22 '11 at 18:36

6 Answers 6

I don't believe name-based SSH is something that will be possible given how the protocol works.

Here are some alternatives.

  • You could do is setup the host that answers for port 22 to act as a gateway. Then you can configure the ssh server to forward requests to the inside based on the key. SSH Gateway example with keys

  • You could adjust your client to use that host as a proxy. That is, it would ssh to the gateway host, and then make use that host to make a connection to the internal host. SSH proxy with client configuration.

  • You could also setup a simple http proxy on the edge. Then use that to allow incoming connections. SSH via HTTP proxy.

Obviously with all the above, making sure you properly configure and lock down the gateway is pretty important.

share|improve this answer

I don't believe this is something that would be possible, at least the way you described, although I would love to be proved wrong. It doesn't appear that the client sends the hostname that it wishes to connect to (at least in the clear). The first step of the SSH connection seems to be to set up encryption.

In addition, you would have issues with host key verification. SSH clients will verify keys based on an IP address as well as a hostname. You would have multiple hostnames with different keys, but the same IP you're connecting to.

A possible solution would be to have a 'bastion' host, where clients can ssh in to that machine, get a normal (or restricted if desired) shell, and can then ssh into internal hosts from there.

share|improve this answer
The bastion concept is what we current have setup but is problematic for my version control (without extra effort). –  ahanson Jul 1 '09 at 19:05
It's super annoying that ssh doesn't send the fqdn and handles the DNS on the client side. I guess people didn't worry about public IP bloat and NAT when most TCP/IP application level protocols were created. Because, seriously, you should be able to do FQDN based NAT with iptables (i.e. kernel filters). –  bias Dec 22 '11 at 18:41
The hostkey could be the key of the reverse proxy. This is a benefit if you trust the security of backend, since you have control of the internal network and hosts. –  rox0r Jun 18 '13 at 21:52
@bias You can't do NAT based on hostname, even if the higher level protocol does send the hostname. The reason it cannot be done is, that the choice of backend has to be done when the SYN packet is received, but the hostname is only sent after the SYN has been processed and a SYN-ACK has been returned. You can however use a very thin application layer proxy for protocols that do send hostname, such as http and https. –  kasperd Jul 8 '14 at 13:57

As the number of ports/hosts you want to access behind a firewall increases, the convenience of VPNs increases.

I don't like VPNs, though.

share|improve this answer

because of how ssh works I think it's not possible. Similar to https you would have to have different (external) IPs for different hosts, because the gateway doesn't know where do you want to connect to because everything in ssh is encryted

share|improve this answer

I am wondering if Honeytrap (the low interaction honeypot) that has a proxy mode couldn't be modified to achieve that.

This honeypot is able to forward any protocol to another computer. Adding a name based vhost system (as implemented by Apache) could make it a perfect reverse proxy for any protocol no ?

I do not have the skills to achieve that but maybe it could be a great project.

share|improve this answer
excellent idea! –  bias Dec 22 '11 at 18:27
The vhost feature in Apache relies on the client sending the hostname before any data has been sent from the server. The SSH protocol doesn't involve such a hostname, so I don't see how you'd even start implementing such a feature. But if you can elaborate on your ideas, I'd be happy to implement a proof of concept or tell you, why it wouldn't work. –  kasperd Jul 8 '14 at 15:01

I have been searching for a solution for this problem on and off for the last half year. But each time I look, it seems impossible to do this with the SSH protocol.

The client does not send the hostname as part of the SSH protocol.

It might send the hostname as part of a DNS lookup, but that might be cached, and the path from client through resolvers to authoritative servers might not cross the proxy, and even if it did there is no robust way of associating specific lookups with specific DNS clients.

There is nothing fancy you can do with the SSH protocol itself either. You have to pick a server without even having seen the SSH version banner from the client. You have to send a banner to the client, before it will send anything to the proxy. The banners from the servers could be different, and you have no chance of guessing, which one is the correct one to use.

Even though this banner is sent unencrypted, you cannot modify it. Every bit of that banner will be verified during connection setup, so you'd be causing a connection failure a bit down the line.

The conclusion to me is pretty clear, one has to change something on the client side in order to make this connectivity work.

Most of the workarounds are encapsulating the SSH traffic inside a different protocol. One could also imagine an addition to the SSH protocol itself, in which the version banner send by the client include the hostname. This can remain compatible with existing severs, since part of the banner is currently specified as a free form identification field, and though clients typically wait for the version banner from the server before sending their own, the protocol does permit the client to send their banner first.

However the solution that worked best for me was actually to use IPv6.

With IPv6 I can have a separate IP address assigned to each server, so the gateway can use the destination IP address to find out which server to send the packet to. The SSH clients might sometimes be running on networks where the only way to get an IPv6 address would be by using Teredo. Teredo is known to be unreliable, but only when the native IPv6 end of the connection is using a public Teredo relay. One can simply put a Teredo relay on the gateway, where you'd run the proxy. Miredo can be installed and configured as a relay in less than five minutes.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.