1
votes

I have setup an SSH server behind haproxy.

haproxy is configured to serve 80/443 ports as L7 load balancer. I have added a TCP frontend to bind on port 22 to handle and route SSH connections.

frontend ssh
    bind *:22
    mode tcp
    option tcplog
    use_backend back_ssh

backend back_ssh
    option tcp-check
    tcp-check expect string SSH-2.0-
    server ssh_server 172.16.2.5:1222 check

the result is as below (400 bad request)

ssh -vvv  foo.bar.com
OpenSSH_7.9p1, LibreSSL 2.7.3
debug1: Reading configuration data /Users/arash/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to foo.bar.com port 22.
debug1: Connection established.
debug1: identity file /Users/arash/.ssh/id_rsa type 0
debug1: identity file /Users/arash/.ssh/id_rsa-cert type -1
debug1: identity file /Users/arash/.ssh/id_dsa type -1
debug1: identity file /Users/arash/.ssh/id_dsa-cert type -1
debug1: identity file /Users/arash/.ssh/id_ecdsa type -1
debug1: identity file /Users/arash/.ssh/id_ecdsa-cert type -1
debug1: identity file /Users/arash/.ssh/id_ed25519 type -1
debug1: identity file /Users/arash/.ssh/id_ed25519-cert type -1
debug1: identity file /Users/arash/.ssh/id_xmss type -1
debug1: identity file /Users/arash/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_7.9
debug1: ssh_exchange_identification: HTTP/1.0 400 Bad request


debug1: ssh_exchange_identification: Cache-Control: no-cache


debug1: ssh_exchange_identification: Connection: close


debug1: ssh_exchange_identification: Content-Type: text/html


debug1: ssh_exchange_identification: 


debug1: ssh_exchange_identification: <html><body><h1>400 Bad request</h1>

debug1: ssh_exchange_identification: Your browser sent an invalid request.

debug1: ssh_exchange_identification: </body></html>

ssh_exchange_identification: Connection closed by remote host

and when I change config to listen instead of frontend and backend like below, it will work.

listen ssh *:22
    mode tcp
    option tcplog
    option tcp-check
    tcp-check expect string SSH-2.0-
    server ssh_server 172.16.2.5:1222 check

The question is did I miss something on my first configuration and how it's broken? I prefer to have my configuration in frontend/backend format to follow my convention.

1
Add mode tcp to the backend?Michael - sqlbot
mode tcp is the default. When you use the frontend/backend config, are you able to see the request in the haproxy logs? Not sure if you're logging. Haproxy has good custom logging options if you want some help there for debugging this.jmoney
@Michael-sqlbot I think haproxy will ignore tcp-check if its not in tcp mode. so it wont help IMO.Arash
@Arash it's apparent that you're in HTTP mode, and this is probably coming from a defaults section that you omitted from the question. A listen proxy declaration is simply a shorthand for declaring a frontend and a backend with the same name and common config, and an implicit use_backend. Kindly try the suggestion rather than dismiss it. You may also need option tcplog if your globals are overriding that, too.Michael - sqlbot
@Michael-sqlbot you were totally correct. Thank you very much (: I wish you have posted it as answer, so I would mark it.Arash

1 Answers

2
votes

A listen foo proxy declaration is essentially a shorthand for declaring a frontend foo and a backend foo with the same name (foo) and an implicit default_backend foo.

But importantly, it's also applying any relevant configuration directives to both the (implicit) frontend and the backend this construct creates.

This is where your configuration diverges -- you don't have mode tcp -- a directive applicable to both frontends and backends -- in your backend proxy declaration. Since TCP (layer 4 balancing) is the default mode, the HTTP appearing in your protocol stream implies that you must also have a defaults section (not shown) that is setting mode http and putting the backend into http mode.