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

Actix-Web搭建HTTPS服务器:ZeroSSL证书引发SSL错误排查

问题描述

我基于Actix-Web搭建了一个简单的HTTPS服务器,使用openssl生成的自签名TLS密钥在本地运行完全正常,但换成ZeroSSL提供的真实密钥后,浏览器无法访问服务:Chrome系浏览器提示ERR_SSL_VERSION_OR_CIPHER_MISMATCH,火狐浏览器提示SSL_ERROR_NO_CYPHER_OVERLAP。

代码实现

async fn main() -> std::io::Result<()> {
    let cert_key_file: PathBuf = PathBuf::from("zerossl/private.key");
    let cert_file: PathBuf = PathBuf::from("zerossl/certificate.crt");
    let cert_ca_file: PathBuf = PathBuf::from("zerossl/ca_bundle.crt");
    // 为了简洁省略了path_to_certificate、path_to_ca、path_to_key的创建逻辑

    let mut local_address = format!("0.0.0.0:{}", SERVICE_PORT);
    let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
    builder
        .set_private_key_file(path_to_key, SslFiletype::PEM)
        .unwrap();
    builder.set_certificate_chain_file(path_to_ca).unwrap();
    builder.set_certificate_file(path_to_certificate, SslFiletype::PEM).unwrap();

    HttpServer::new(|| {
        App::new()
            //.route("/{filename:.*}", web::get().to(index))
            .route("/hello", web::get().to(|| async { "Hello World!" }))
            .service(greet)
    })
    .bind_openssl(local_address, builder)?
    .run()
    .await
}

补充调试信息(curl输出)

➜  release git:(master) curl -v https://zavijavasoft.com:8080
*   Trying 37.140.197.152:8080...
* TCP_NODELAY set
* Connected to zavijavasoft.com (37.140.197.152) port 8080 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, handshake failure (552):
* error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
* Closing connection 0
curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

请问我哪里操作出错了?


解决方案

问题出在SSL证书链的加载顺序和方式上,调整以下两点即可解决:

  1. 修正证书加载顺序:必须先加载主证书(certificate.crt),再加载CA证书链(ca_bundle.crt)。你当前的代码先调用了set_certificate_chain_file,后调用set_certificate_file,这会导致SSL握手时无法正确构建完整的信任链,进而引发加密套件不匹配的错误。

  2. 正确的代码修改:

let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
// 第一步:加载私钥
builder.set_private_key_file(path_to_key, SslFiletype::PEM).unwrap();
// 第二步:加载主证书
builder.set_certificate_file(path_to_certificate, SslFiletype::PEM).unwrap();
// 第三步:加载CA证书链
builder.set_certificate_chain_file(path_to_ca).unwrap();

另外,还有一种更稳妥的替代方案:将certificate.crt的内容和ca_bundle.crt的内容合并到同一个PEM文件中(主证书内容在前,CA bundle内容在后),然后只调用set_certificate_chain_file加载这个合并后的文件,这样可以彻底避免顺序问题。

修改完成后重启服务器,浏览器和curl就能正常建立SSL连接了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:35:24