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

Docker Compose部署Node.js应用遇SSL握手错误及502网关问题求助

解决Nginx Proxy + Let's Encrypt测试证书下的SSL_do_handshake() failed (wrong version number)及502错误

问题核心分析

这个错误本质是SSL/TLS版本不匹配,再结合502网关错误,大概率是Nginx Proxy配置中强制用SSL协议转发到仅支持HTTP的Express后端,或是Docker网络、证书配置出了问题。

分步排查与解决

1. 修正Nginx到后端的转发协议

你的Express应用直接IP访问正常(HTTP),所以Nginx在443端口处理SSL后,必须用HTTP转发请求到后端,不能强制SSL连接:

  • 检查对应域名的Nginx server块,确保proxy_pass指向后端的HTTP地址:
    server {
        listen 443 ssl;
        server_name your-subdomain.example.com;
    
        ssl_certificate /etc/nginx/certs/your-subdomain.example.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/your-subdomain.example.com/privkey.pem;
    
        location / {
            # 重点:用http://指向后端服务,不要加https
            proxy_pass http://express-app: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;
        }
    }
    
  • 删掉任何proxy_ssl_protocols、proxy_ssl_verify这类强制后端SSL的配置项。

2. 规范Docker Compose网络与环境变量

所有容器必须在同一网络内通信,同时环境变量要准确对应:

version: '3.8'
networks:
  app-network:
    driver: bridge

services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./certs:/etc/nginx/certs
      - ./vhost:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
    networks:
      - app-network

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./certs:/etc/nginx/certs
      - ./vhost:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
    environment:
      - NGINX_PROXY_CONTAINER=nginx-proxy
      - ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory # 测试版CA地址
    networks:
      - app-network

  express-app:
    build: .
    environment:
      - VIRTUAL_HOST=your-subdomain.example.com
      - VIRTUAL_PORT=3000 # 必须和Express监听的端口一致
      - LETSENCRYPT_HOST=your-subdomain.example.com
      - LETSENCRYPT_EMAIL=your-email@example.com
    networks:
      - app-network
    # 无需暴露3000端口到主机,内部网络即可通信
  • 确认VIRTUAL_PORT和Express代码中app.listen()的端口完全匹配,默认是3000。

3. 验证Let's Encrypt测试证书完整性

测试版证书可能存在证书链不完整的情况:

  • 进入nginx-proxy容器查看证书链:
    docker exec -it nginx-proxy cat /etc/nginx/certs/your-subdomain.example.com/fullchain.pem
    
  • 如果只有一张证书,手动下载Let's Encrypt测试根证书(Staging Root X1),追加到fullchain.pem末尾,然后重启nginx-proxy:
    docker-compose restart nginx-proxy
    

4. 调整Nginx全局SSL配置

确保SSL协议版本兼容,避免握手时版本不匹配:

  • 在./vhost/default文件中添加全局SSL配置:
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
  • 重启nginx-proxy生效。

5. 检查端口与防火墙

  • 确认EC2安全组开放80、443端口,入站规则允许所有IP访问。
  • 检查服务器本地防火墙(如ufw)是否放行端口:
    sudo ufw status
    

快速验证流程

  1. 停止所有容器:docker-compose down
  2. 清理旧证书:rm -rf ./certs/*
  3. 重新启动容器:docker-compose up -d
  4. 查看Nginx日志排查错误:docker-compose logs nginx-proxy
  5. 用curl测试握手:curl -v https://your-subdomain.example.com,观察详细错误信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:27:15