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

Nginx SSL透传至Spring Boot服务器握手失败问题排查

问题描述

本地8081端口运行Spring Boot应用,通过自签名证书启用HTTPS,同时启用客户端MTLS认证。需要让Nginx以透传模式(当前配置为反向代理HTTPS到Spring Boot)工作,但出现SSL握手失败错误,报错信息为SSL_do_handshake() failed (SSL: error:0A000412:SSL routines::sslv3 alert bad certificate:SSL alert number 42)。

证书生成步骤

1. 创建CA证书

openssl req \
  -new \
  -x509 \
  -nodes \
  -newkey rsa:2048\
  -days 365 \
  -subj '/CN=bcc' \
  -keyout ca.key \
  -out ca.crt

2. 生成Spring Boot服务器证书

openssl genrsa \
  -out server.key 2048

openssl req \
  -new \
  -key server.key \
  -subj '/CN=bcc-ca-website.org' \
  -out server.csr

openssl x509 \
  -req \
  -in server.csr \
  -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -days 365 \
  -extfile v3.ext \
  -out server.crt

3. 生成Nginx服务器证书

openssl genrsa \
  -out nginx-server.key 2048

openssl req \
  -new \
  -key nginx-server.key \
  -subj '/CN=bcc-ca-website.org' \
  -out nginx-server.csr

openssl x509 \
  -req \
  -in nginx-server.csr \
  -CA ca.crt \
  -CAkey ca.key \
  -CAcreateserial \
  -days 365 \
  -extfile v3.ext \
  -out nginx-server.crt

Spring Boot配置(application.yml)

server:  
  port: 8081  
  ssl:  
    enabled: true  
    key-store: "classpath:server.p12"  
    key-store-password: 123456  
    key-store-type: PKCS12  
    client-auth: need  
    enabled-protocols: TLSv1.2  

    trust-store: "classpath:server.p12"  
    trust-store-type: pkcs12  
    trust-store-password: 123456  

注:已启用客户端MTLS认证,客户端CA及证书通过相同方式创建。

Nginx配置(sites-available/default)

upstream node_basic {
    server                  localhost:8081;

}

server {
    listen                  80;

    location / {
        return              301 https://$host$request_uri;
    }
}

server {
    listen                  443 ssl;

    ssl_certificate         /etc/ssl/nginx-server.crt;
    ssl_certificate_key     /etc/ssl/nginx-server.key;
    ssl_protocols           TLSv1.2 TLSv1.3;
    ssl_ciphers             HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers  on;
    ssl_session_cache    shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions
    ssl_session_timeout  24h;

    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-NginX-Proxy true;

        proxy_pass           https://node_basic;
    }
}

错误信息

2023/02/02 11:37:51 [error] 22475#22475: *1 SSL_do_handshake() failed (SSL: error:0A000412:SSL routines::sslv3 alert bad certificate:SSL alert number 42) while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET / HTTP/1.1", upstream: "https://127.0.0.1:8081/", host: "bcc-ca-website.org"

排查与修复方案

1. 核心问题定位

错误alert bad certificate:SSL alert number 42表明:Spring Boot启用了client-auth: need,要求上游请求必须提供合法的客户端证书,但当前Nginx向Spring Boot发起HTTPS请求时,未携带符合要求的客户端证书,导致握手被拒绝。

2. 具体修复步骤

步骤1:为Nginx准备合法的客户端证书

将已创建的客户端证书和密钥整理为Nginx可读取的格式:

# 若需打包为PKCS12格式(可选)
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "client"

输入密码时设置为固定值,比如123456

步骤2:配置Nginx向上游发送客户端证书

修改Nginx的server块,在proxy_pass配置前添加以下内容:

# 配置向上游发送的客户端证书
proxy_ssl_certificate /etc/ssl/client.crt;
proxy_ssl_certificate_key /etc/ssl/client.key;

# 配置信任上游服务器的CA(即你的自签名CA)
proxy_ssl_trusted_certificate /etc/ssl/ca.crt;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;

确保证书文件路径正确,且Nginx进程有权限读取这些文件。

步骤3:修正Spring Boot的Trust Store配置

当前Spring Boot的trust-store指向server.p12,该文件仅包含服务器证书,未包含信任的客户端CA证书。需将客户端CA证书导入到独立的trust store:

keytool -importcert -file client-ca.crt -alias client-ca -keystore truststore.p12 -storetype PKCS12 -storepass 123456

然后修改application.yml中的trust-store配置:

trust-store: "classpath:truststore.p12"

步骤4:验证证书有效性

检查客户端证书是否被Spring Boot的trust store信任:

openssl verify -CAfile client-ca.crt client.crt

3. 若需真正的SSL透传(TCP转发)

如果需求是Nginx不终止SSL,直接将TCP流量转发给Spring Boot,需使用Nginx的stream模块,配置示例:

stream {
    upstream spring_boot {
        server localhost:8081;
    }

    server {
        listen 443;
        proxy_pass spring_boot;
    }

    server {
        listen 80;
        return 301 https://$host$request_uri;
    }
}

此模式下SSL握手直接在客户端与Spring Boot之间完成,Nginx仅做TCP转发,无需处理证书配置,但需确保Nginx已启用stream模块。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 08:45:21