haproxy 在 ssh 连接 [TCP frontend/backend] 上发送 400 错误请求

haproxy sending 400 Bad request on ssh connect [TCP frontend/backend]

我在 haproxy 后面设置了一个 SSH 服务器。

haproxy 配置为 80/443 端口作为 L7 负载均衡器。 我添加了一个 TCP 前端绑定到端口 22 以处理和路由 SSH 连接。

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

结果如下(400个错误请求)

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

当我将配置更改为侦听而不是如下所示的前端和后端时,它将起作用。

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

问题是我是否遗漏了我的第一个配置中的某些内容以及它是如何损坏的? 我更喜欢 frontend/backend 格式的配置以遵循我的约定。

一个listen foo代理声明本质上是一个shorthand,用于声明一个frontend foo和一个具有相同名称(foo)的backend foo和一个隐含的default_backend foo.

但重要的是,它还将任何相关的配置指令应用于此构造创建的(隐式)前端和后端。

这是您的配置出现分歧的地方——您在后端代理声明中没有 mode tcp——适用于前端和后端的指令。由于 TCP(第 4 层平衡)是默认模式,出现在您的协议流中的 HTTP 意味着您还必须有一个设置 mode http 并将后端放入 http 的 defaults 部分(未显示)模式。