Nginx Stream无法正确代理至Node.js SMTP服务的问题排查求助
问题分析与解决方案
核心问题在于Nginx启用了Proxy Protocol,但后端Node.js的SMTP服务器未处理该协议。Proxy Protocol会在TCP连接建立时发送一段特殊格式的头部数据,而你的SMTP服务器无法识别这段数据,会将其视为无效的SMTP命令,因此返回421 You talk too soon错误,同时拒绝后续连接。
解决方案1:禁用Nginx的Proxy Protocol(最简单)
如果不需要获取客户端真实IP等Proxy Protocol提供的信息,直接移除Nginx配置中的proxy_protocol on;即可:
修改后的Nginx Stream配置:
stream { access_log /var/log/nginx/tcp_access.log main; error_log /var/log/nginx/tcp_error.log; upstream tcp_backend { server 127.0.0.1:9001; } server { listen 587; proxy_pass tcp_backend; # 移除 proxy_protocol on; 这一行 } }
执行以下命令验证并重启Nginx:
nginx -t systemctl reload nginx
解决方案2:让Node.js SMTP服务器支持Proxy Protocol(如需保留该功能)
如果需要通过Proxy Protocol获取客户端真实IP,需在Node服务中先解析Proxy Protocol头部,再将处理后的连接转发给SMTP服务器:
步骤1:安装依赖
npm install proxy-protocol-js
步骤2:修改SMTP服务代码
const net = require('net'); const { ProxyProtocol } = require('proxy-protocol-js'); const SMTPServer = require('smtp-server').SMTPServer; const setupSMTPServer = (port) => { const smtpServer = new SMTPServer({ authOptional: false, requireTLS: true, secure: false, key: tlsOptions.key, cert: tlsOptions.cert, onAuth: async (auth, session, callback) => { console.log('Auth Attempt'); // 你的认证逻辑,示例:允许合法用户 callback(null, { user: 'authorized-user' }); }, onData(stream, session, callback) { console.log('onData Received'); let data = ""; stream.on("data", (chunk) => { data += chunk; }); stream.on("end", async () => { parseEmail(data).then((parsedData) => { console.log('Received instruction to send email'); }); callback(); // 必须调用callback结束数据处理 }); }, }); // 创建TCP服务器处理Proxy Protocol头部 const tcpServer = net.createServer((socket) => { socket.once('data', (buffer) => { try { const proxyProtocol = ProxyProtocol.parse(buffer); // 可通过 proxyProtocol.sourceAddress 获取客户端真实IP // 将剩余数据和socket转发给SMTP服务器 smtpServer._handleConnection(socket, buffer.slice(proxyProtocol.getTotalLength())); } catch (err) { console.error('Proxy Protocol解析失败:', err); socket.end('421 Invalid connection'); } }); }); tcpServer.listen(9001, "0.0.0.0", () => { console.log(`SMTP server (支持Proxy Protocol) 监听端口9001`); }); // 新增错误监听,排查服务问题 smtpServer.on('error', (err) => { console.error('SMTP服务器错误:', err); }); };
额外检查点
- 验证Node服务监听状态:执行
ss -tulpn | grep 9001,确保输出包含0.0.0.0:9001及你的Node进程ID。 - 确认SMTP客户端支持STARTTLS:你的Node服务设置了
requireTLS: true,客户端必须先发起STARTTLS升级才能继续操作。 - 检查Node服务日志:确保没有TLS证书加载失败、端口占用等报错。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

