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

添加SSL证书后NestJS后端故障,请求排查解决

问题解决:NestJS添加SSL后Nginx反向代理连接失败(错误111)及404问题

问题概述

基于NestJS开发的后端启用SSL后无法正常运行,此前HTTP协议下一切正常。Nginx反向代理至后端时出现连接失败错误(错误码111),直接curl测试后端返回404。已尝试调整Nginx配置、修改SSL证书权限,问题仍未解决。

相关配置与日志

Nginx配置

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-A>

    root /var/www/html;
    index index.html index.htm;

    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header Content-Security-Policy upgrade-insecure-requests;

    # frontend
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    # backend
    location /api/ {
        proxy_pass https://127.0.0.1:5001/; 
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

NestJS主文件(main.ts)

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as fs from 'fs';
import * as https from 'https';

async function bootstrap() {
  const httpsOptions = {
    key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/example.com/fullchain.pem'),
  };

  const app = await NestFactory.create(AppModule, {
    httpsOptions,
  });

 await app.listen(5001, () => {
  console.log('Server is running on https://localhost:5001');
 });

}
bootstrap();

Nginx日志

2025/01/17 17:05:07 [error] 325374#325374: *278 connect() failed (111: Unknown error) while connecting to upstream, client: 149.154.161.248, server: example.com, request: "GET /api/ HTTP/1.1", upstream: "https://127.0.0.1:5001/", host: "example.com"
2025/01/17 17:05:17 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/ HTTP/1.1", upstream: "https://127.0.0.1:5001/", host: "example.com", referrer: "https://web.telegram.org/"
2025/01/17 17:05:22 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:06:08 [error] 325374#325374: *284 connect() failed (111: Unknown error) while connecting to upstream, client: 149.154.161.201, server: example.com, request: "GET /api/ HTTP/1.1", upstream: "https://127.0.0.1:5001/", host: "example.com"
2025/01/17 17:06:28 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:06:28 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:06:29 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:06:29 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:06:29 [error] 325374#325374: *280 connect() failed (111: Unknown error) while connecting to upstream, client: 80.242.211.179, server: example.com, request: "GET /api/hello HTTP/1.1", upstream: "https://127.0.0.1:5001/hello", host: "example.com"
2025/01/17 17:07:09 [error] 325374#325374: *297 connect() failed (111: Unknown error) while connecting to upstream, client: 149.154.161.218, server: example.com, request: "GET /api/ HTTP/1.1", upstream: "https://127.0.0.1:5001/", host: "example.com"

curl测试结果

{"message":"Cannot GET /","error":"Not Found","statusCode":404}

解决方案

1. 确认NestJS服务是否正常监听端口

先检查5001端口是否被NestJS进程占用:

netstat -tulpn | grep 5001
# 或用ss命令
ss -tulpn | grep 5001

如果无输出,说明NestJS未启动或监听失败,大概率是证书读取权限问题。

2. 修复NestJS的证书读取权限

Let's Encrypt证书目录默认权限为root:root,若NestJS以非root用户运行,会无法读取证书。解决方式:

  • 临时测试:给证书目录添加可读权限(不推荐长期使用)
sudo chmod -R 755 /etc/letsencrypt/live/
sudo chmod -R 755 /etc/letsencrypt/archive/
  • 长期方案:复制证书到NestJS项目目录并修改权限
sudo cp /etc/letsencrypt/live/example.com/fullchain.pem /path/to/your/nestjs/project/
sudo cp /etc/letsencrypt/live/example.com/privkey.pem /path/to/your/nestjs/project/
sudo chown your-user:your-group /path/to/your/nestjs/project/*.pem

然后修改main.ts中的证书路径:

const httpsOptions = {
  key: fs.readFileSync('./privkey.pem'),
  cert: fs.readFileSync('./fullchain.pem'),
};

3. 简化架构:Nginx处理SSL,后端用HTTP通信

既然Nginx已作为SSL终端,后端无需再启用SSL,可避免SSL握手问题并提升性能。修改main.ts去掉HTTPS配置:

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(5001, () => {
    console.log('Server is running on http://localhost:5001');
  });
}
bootstrap();

再修改Nginx的location /api/配置,将proxy_pass改为HTTP:

location /api/ {
    proxy_pass http://127.0.0.1:5001/; 
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

4. 修复curl测试的404问题

若坚持后端启用SSL,curl测试必须使用HTTPS协议并指定正确路径:

curl -k https://localhost:5001/api/hello

-k参数用于忽略证书验证问题(测试环境适用)。同时检查NestJS控制器是否添加了@Controller('api')前缀,确保路由路径匹配。

5. 修复Nginx的ssl_ciphers配置

你的Nginx配置中ssl_ciphers被截断,补全为完整的安全 cipher 列表:

ssl_ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305-SHA256;

验证步骤

  1. 重启NestJS服务:pm2 restart your-nest-app(若用pm2管理)或直接重启进程
  2. 重启Nginx:sudo systemctl restart nginx
  3. 测试后端:curl http://localhost:5001/api/hello(后端用HTTP)或curl -k https://localhost:5001/api/hello(后端用HTTPS)
  4. 测试外部访问:访问https://example.com/api/hello查看是否正常返回

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 22:05:54