添加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;
验证步骤
- 重启NestJS服务:
pm2 restart your-nest-app(若用pm2管理)或直接重启进程 - 重启Nginx:
sudo systemctl restart nginx - 测试后端:
curl http://localhost:5001/api/hello(后端用HTTP)或curl -k https://localhost:5001/api/hello(后端用HTTPS) - 测试外部访问:访问
https://example.com/api/hello查看是否正常返回
内容的提问来源于stack exchange,提问作者Dimash
相关产品推荐
相关产品推荐

