本文通过仅监听回环地址的中转端口处理 PROXY protocol 与 SSH 的协议差异。去掉 PROXY protocol 后,sshd 仍无法从 TCP 连接直接取得原始客户端地址。
SSH/SFTP 经 Nginx stream 后无法握手,有时会出现 invalid packet length 或 packet too large。这只是可能的症状;需要结合前后端配置和日志确认原因。proxy_protocol on 会在 TCP 数据前加入连接元数据,普通 OpenSSH sshd 不解析它,因而可能把它当成 SSH 协议数据。
如果入口只用于 SSH,最直接的修复是去掉发送侧的 proxy_protocol on。如果同一入口还要给 HTTPS 后端传递地址,可以让 SSH 分支先经过一个解析并去掉前缀的本地中转:
stream {
upstream ssh_strip { server 127.0.0.1:2222; }
upstream https_backend { server 127.0.0.1:8443; }
map $ssl_preread_protocol $backend {
"" ssh_strip;
default https_backend;
}
server {
listen 443;
listen [::]:443;
ssl_preread on;
proxy_protocol on;
proxy_pass $backend;
}
server {
listen 127.0.0.1:2222 proxy_protocol;
proxy_protocol off;
proxy_pass 127.0.0.1:22;
}
}
HTTPS 后端的 127.0.0.1:8443 必须按接收 PROXY protocol 的示例配置 TLS 监听。SSH 中转的 listen ... proxy_protocol 接收并移除前缀,proxy_protocol off 阻止再次发送,最后才把原始 SSH 流送给 sshd。不要把该中转端口监听到所有 IPv4/IPv6 地址,它没有独立的客户端认证。
这个中转解决了协议不兼容,但 sshd 的 TCP 对端仍是 Nginx。需要审计原始地址时,可在入口 stream 记录连接日志;依赖 sshd 日志地址的封禁规则应重新评估,不能把 loopback 地址视为外部用户。
执行 nginx -t 并 reload,保留原 SSH 管理连接,然后从外部测试 ssh -p 443 user@host、sftp -P 443 user@host 和正常 HTTPS。若错误仍在,继续检查端口是否指回自身、是否连到了非 SSH 服务,以及两端的 PROXY protocol 是否成对启用。配置检查通过后仍需实际连接测试。
评论区