You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
  });
};

额外检查点

  1. 验证Node服务监听状态:执行ss -tulpn | grep 9001,确保输出包含0.0.0.0:9001及你的Node进程ID。
  2. 确认SMTP客户端支持STARTTLS:你的Node服务设置了requireTLS: true,客户端必须先发起STARTTLS升级才能继续操作。
  3. 检查Node服务日志:确保没有TLS证书加载失败、端口占用等报错。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:54:54