
1. 项目概述为什么国密证书在当下变得如此重要最近在给一个对数据安全有严格要求的政企客户部署Web服务时遇到了一个“甜蜜的烦恼”。客户明确要求对外服务的网站必须使用国密算法SM2的SSL证书并且要确保在包括360浏览器在内的主流国产化环境中能正常访问。这让我把目光投向了阿里云——作为国内云服务的领头羊它提供了国密证书的申请与管理服务。听起来很简单不就是申请个证书然后配到Nginx上吗但实际操作下来从证书申请、格式转换到Nginx编译、配置再到最后的浏览器兼容性测试几乎每一步都有“坑”在等着你。特别是让Nginx原生支持国密SSLGMSSL以及确保360浏览器能正确识别并信任证书链这两个环节耗费了我大量的调试时间。所以我决定把这次从零开始在阿里云ECS上部署支持SM2国密证书的Nginx服务的完整过程以及过程中遇到的所有典型问题和解决方案系统地记录下来。这不仅仅是一份配置指南更是一份“避坑实录”。无论你是运维工程师、开发人员还是对国密改造感兴趣的技术爱好者这篇文章都能帮你绕过我踩过的那些坑快速、稳定地完成部署。国密算法是国家密码管理局颁布的自主可控密码算法标准其中SM2用于非对称加密和签名正在金融、政务、能源等关键领域加速推广。掌握它的实战部署已经从一个加分项变成了许多项目的必备技能。2. 核心需求与方案选型解析2.1 国密SSL与国际标准SSL的核心差异在动手之前我们必须搞清楚国密SSL和国际通用的RSA/ECC SSL到底有什么不同。这决定了我们不能简单地把一个RSA证书换成SM2证书就了事。首先算法栈完全不同。我们熟悉的RSA SSL/TLS其算法套件通常是这样的密钥交换用RSA或ECDHE签名用RSA对称加密用AES摘要算法用SHA256。而国密SSL通常基于TLS 1.1/1.2的国密改造版本如GM/T 0024标准则是一套完整的国产替代方案密钥交换和签名使用SM2椭圆曲线算法对称加密使用SM4算法摘要算法则使用SM3。这意味着客户端和服务器必须同时支持这套国密算法套件才能成功握手。其次证书格式和编码存在兼容性问题。国际标准的证书通常是X.509格式采用DER或PEM编码。国密证书虽然也基于X.509v3格式但其公钥信息是SM2公钥并且证书中会包含特定的国密扩展字段。一些传统的工具如老版本的OpenSSL可能无法直接识别或正确解析SM2证书。更重要的是证书链的信任锚不同。RSA证书链的根通常是GlobalSign、DigiCert等国际CA而SM2证书链的根是国内的国密根CA例如“CFCA OV SM2 CA”等。如果客户端的信任根证书库Trust Store里没有预置这些国密根CA就会提示证书不受信任。基于以上差异我们的技术方案必须解决两个核心问题1. 如何让Nginx支持国密算法套件2. 如何确保客户端尤其是360浏览器能正确验证国密证书链2.2 技术方案选型Tongsuo vs. Nginx原生模块要让Nginx支持国密主要有两种主流路径方案一使用Tongsuo原BabaSSL国密开源库替换OpenSSL并编译Nginx。这是目前最主流、兼容性最好的方案。Tongsuo是阿里云开源并维护的一个提供国密算法和国密协议能力的密码学库它完全兼容OpenSSL的API。你可以把它理解为“支持国密的OpenSSL增强版”。Nginx在编译时链接Tongsuo库就能原生支持国密SSL协议包括ssl_ciphers指令可以直接配置诸如ECC-SM2-WITH-SM4-SM3这样的国密套件。这个方案性能好符合标准是生产环境的首选。方案二使用Nginx的第三方国密模块如nginx-gmssl-module。这个方案是在标准Nginx和OpenSSL的基础上通过一个额外的模块来添加国密支持。它可能对Nginx版本有特定要求并且其维护性和与主流Nginx新特性的同步可能不如方案一。它更像是一个“补丁”。我的选择与理由我毫不犹豫地选择了方案一Tongsuo Nginx。原因有三第一Tongsuo由阿里云官方维护与阿里云国密证书服务的兼容性理论上最好出了问题也更容易找到支持。第二它是底层密码库的替换更加彻底和标准减少了因模块兼容性带来的不确定性。第三社区活跃文档和案例相对丰富。本文的后续所有步骤都将基于这个方案展开。2.3 环境与工具准备清单在开始编译和配置之前请确保你的服务器以CentOS 7.x为例已经准备好以下环境一台阿里云ECS实例建议选择CentOS 7.9或Alibaba Cloud Linux 3。本文以CentOS 7.9为例。基础开发工具gcc,gcc-c,make,pcre-devel,zlib-devel等用于编译软件。yum groupinstall -y Development Tools yum install -y pcre pcre-devel zlib zlib-devel源码包tongsuo国密密码库。我们将从官方GitHub仓库克隆或下载Release包。nginxWeb服务器。建议选择稳定的1.20.x或1.24.x版本。阿里云国密证书提前在阿里云SSL证书控制台申请免费的SM2国密证书或购买OV/EV型国密证书。申请时记得证书类型选择“国密”。申请成功后你将能下载到一个包含以下文件的压缩包yourdomain_name_chain.pem证书链文件包含服务器证书和中间CA证书。yourdomain_name.keySM2私钥文件。yourdomain_name.pem服务器证书文件通常与链文件中的第一个相同。yourdomain_name.pfxPKCS#12格式的证书包某些场景下备用。3. 实战部署从编译到配置的全过程3.1 编译支持国密的Tongsuo密码库这是整个流程中最关键的一步。我们不是在系统里安装Tongsuo而是将它编译成静态库或动态库供后续编译Nginx时链接。步骤1获取源码并解压通过Git克隆最新代码或者下载稳定的Release版本。这里以克隆为例cd /usr/local/src git clone https://github.com/Tongsuo-Project/Tongsuo.git cd Tongsuo如果网络不畅也可以去GitHub的Release页面下载tar.gz包。步骤2配置编译选项Tongsuo的配置脚本参数非常丰富为了支持国密SSL我们需要启用相关选项。./config --prefix/usr/local/tongsuo \ enable-ntls \ enable-sm2 \ enable-sm3 \ enable-sm4 \ enable-sms4 \ no-shared--prefix指定安装目录。enable-ntls启用国密SSL协议NTLS是国密SSL的一种实现。enable-sm2/sm3/sm4启用对应的国密算法。no-shared编译静态库.a文件。对于Nginx编译使用静态库可以避免运行时依赖问题更推荐。如果你想用动态库则去掉此参数。步骤3编译与安装make -j $(nproc) # 使用多核并行编译加快速度 make install编译完成后国密算法库和相关头文件就安装到了/usr/local/tongsuo目录下。最重要的文件是/usr/local/tongsuo/lib/libcrypto.a和/usr/local/tongsuo/lib/libssl.a静态库。实操心得编译过程可能会因为缺少依赖而报错。常见的错误是提示perl模块缺失。请确保系统已安装perl和perl-IPC-Cmd。如果遇到其他错误仔细查看错误输出通常是某个开发包没装用yum search和yum install解决即可。3.2 编译集成Tongsuo的Nginx现在我们用刚才编译好的Tongsuo库来编译Nginx。步骤1获取Nginx源码并解压cd /usr/local/src wget http://nginx.org/download/nginx-1.24.0.tar.gz tar zxvf nginx-1.24.0.tar.gz cd nginx-1.24.0步骤2配置Nginx链接Tongsuo静态库这是核心配置步骤--with-cc-opt和--with-ld-opt参数用于指定额外的编译和链接标志将Nginx指向我们自编译的Tongsuo。./configure --prefix/usr/local/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_stub_status_module \ --with-stream \ --with-stream_ssl_module \ --with-cc-opt-I/usr/local/tongsuo/include \ --with-ld-opt-L/usr/local/tongsuo/lib -lssl -lcrypto -lpthread -ldl--with-http_ssl_module启用HTTP SSL模块这是必须的。--with-cc-opt-I/usr/local/tongsuo/include告诉编译器去/usr/local/tongsuo/include目录下寻找Tongsuo的头文件。--with-ld-opt-L/usr/local/tongsuo/lib -lssl -lcrypto告诉链接器去/usr/local/tongsuo/lib目录下寻找Tongsuo的库文件libssl.a和libcrypto.a并链接它们。步骤3编译并安装Nginxmake -j $(nproc) make install安装完成后Nginx的可执行文件位于/usr/local/nginx/sbin/nginx。步骤4验证Nginx是否支持国密启动Nginx前先检查其编译信息确认SSL和国密相关模块已正确集成。/usr/local/nginx/sbin/nginx -V在输出信息中你应该能看到--with-http_ssl_module并且configure arguments:里包含你指定的Tongsuo路径。更直接的验证是启动Nginx后用支持国密的客户端如后续测试的360浏览器尝试连接。3.3 配置Nginx使用SM2国密证书编译成功只是万里长征第一步正确的配置才能让服务跑起来。这里有几个关键点极易出错。步骤1准备证书文件将从阿里云下载的证书包上传到服务器例如放到/usr/local/nginx/conf/ssl/目录下。你需要的主要是两个文件yourdomain_name.keySM2私钥。yourdomain_name_chain.pem证书链文件。重要提示请务必检查私钥文件的格式。阿里云下载的SM2私钥通常是PKCS#8格式的PEM文件。使用openssl ec -in yourdomain_name.key -text -noout命令查看如果开头是-----BEGIN PRIVATE KEY-----那就是PKCS#8格式。Nginx的ssl_certificate_key指令可以直接识别这种格式。如果开头是-----BEGIN EC PRIVATE KEY-----PKCS#1格式可能需要转换但阿里云下载的一般无需转换。步骤2编辑Nginx配置文件编辑/usr/local/nginx/conf/nginx.conf在http块内配置一个支持国密的server。http { ... server { listen 443 ssl http2; # 启用HTTP/2 server_name yourdomain.com www.yourdomain.com; # 指定国密证书和私钥 ssl_certificate /usr/local/nginx/conf/ssl/yourdomain_name_chain.pem; ssl_certificate_key /usr/local/nginx/conf/ssl/yourdomain_name.key; # 国密SSL协议配置关键 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Tongsuo国密通常基于TLS 1.1/1.2 # 配置国密密码套件优先 ssl_ciphers ECC-SM2-WITH-SM4-SM3:ECDHE-SM2-WITH-SM4-SM3:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; # 优化SSL性能与安全 ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ... # 其他location等配置 } }配置解析与避坑点ssl_ciphers指令这是国密配置的灵魂。ECC-SM2-WITH-SM4-SM3是标准的国密套件。我们将它放在最前面表示服务器优先使用国密套件与客户端协商。后面跟的ECDHE-RSA-AES128-GCM-SHA256是国际通用套件用于向后兼容不支持国密的浏览器如Chrome、Firefox。这样配置可以实现国密自适应支持国密的客户端如360浏览器走国密链路不支持的走国际标准链路。证书链文件必须使用从阿里云下载的*_chain.pem文件。这个文件包含了你的服务器证书和中间CA证书。如果只使用服务器证书文件*.pem客户端在验证时可能无法找到完整的证书链导致握手失败或证书不受信任的错误。私钥权限确保私钥文件.key的权限是600-rw-------并且所有者是启动Nginx的用户通常是root或nginx防止权限问题导致Nginx启动失败。chmod 600 /usr/local/nginx/conf/ssl/yourdomain_name.key chown root:root /usr/local/nginx/conf/ssl/yourdomain_name.key步骤3启动Nginx并检查配置# 测试配置文件语法 /usr/local/nginx/sbin/nginx -t # 如果显示“syntax is ok”和“test is successful”则启动 /usr/local/nginx/sbin/nginx # 设置开机自启可选 echo /usr/local/nginx/sbin/nginx /etc/rc.local chmod x /etc/rc.local4. 兼容性测试与问题深度排查配置完成后访问你的网站你会发现第一个大坑Chrome和Firefox可能会提示“不安全连接”。别慌这是正常的因为它们默认不信任国密根CA。我们的重点测试对象是360浏览器等支持国密的国产浏览器。4.1 360浏览器兼容性测试实录在Windows或国产化操作系统上使用最新版的360安全浏览器或360极速浏览器访问你的HTTPS站点。预期成功现象地址栏显示绿色的安全锁标志。点击锁标志查看证书详情应能看到证书是由“CFCA”或“上海CA”等国内CA机构签发并且“签名算法”显示为“sm2-with-sm3”或类似字样。浏览器没有弹出任何安全警告。如果失败可能遇到以下几种情况及排查思路情况一浏览器提示“证书不受信任”或“证书错误”。排查点1证书链不完整。这是最常见的原因。确保Nginx配置中ssl_certificate指向的是*_chain.pem文件。你可以用命令检查这个文件内容cat yourdomain_name_chain.pem应该看到至少两个-----BEGIN CERTIFICATE-----块第一个是你的服务器证书第二个是中间CA证书。排查点2国密根CA未安装。虽然360浏览器等通常预置了主流国密根CA但在某些定制化或旧版本系统中可能没有。你需要手动将国密根CA证书导入到系统的受信任根证书存储区。根证书可以从你的证书颁发机构CA处获取或者从阿里云证书服务帮助文档中查找。排查点3服务器证书与域名不匹配。检查申请证书时填写的域名Common Name和当前访问的域名是否完全一致包括www前缀。情况二浏览器无法连接ERR_SSL_VERSION_OR_CIPHER_MISMATCH。排查点1Nginx的ssl_ciphers配置错误。确认配置的国密套件字符串ECC-SM2-WITH-SM4-SM3拼写正确。可以尝试简化配置只保留这一个套件进行测试。排查点2Tongsuo编译时国密支持未开启。重新检查Tongsuo的编译配置确保enable-ntls,enable-sm2等参数已启用。排查点3客户端不支持国密。如果你用Chrome测试出现这个错误是正常的。请务必使用360浏览器进行国密链路测试。情况三连接成功但浏览器显示“TLS 1.0”等旧协议。排查点检查Nginx配置中的ssl_protocols。国密SSL通常基于TLS 1.1或TLS 1.2。确保配置中包含TLSv1.1 TLSv1.2。如果只配置了TLSv1.3而Tongsuo的国密实现可能尚未完全适配TLS 1.3则会导致握手失败。4.2 使用OpenSSL/Tongsuo命令行工具进行诊断当浏览器测试不直观时命令行工具是强大的诊断武器。由于我们编译了Tongsuo它提供了与OpenSSL兼容的命令行工具。1. 测试服务器国密套件支持情况使用Tongsuo的s_client并指定国密套件进行连接测试。# 使用Tongsuo的openssl命令行工具 /usr/local/tongsuo/bin/openssl s_client -connect localhost:443 -cipher ECC-SM2-WITH-SM4-SM3如果连接成功会打印出详细的握手信息包括证书链、使用的密码套件等。如果失败会给出明确的错误信息如“no shared cipher”表示套件不匹配。2. 验证证书链和私钥是否匹配# 验证私钥 /usr/local/tongsuo/bin/openssl ec -in yourdomain_name.key -text -noout # 验证证书 /usr/local/tongsuo/bin/openssl x509 -in yourdomain_name.pem -text -noout # 检查私钥与证书是否配对使用国密算法验证签名此命令可能需要根据Tongsuo版本调整 # 通常可以用以下命令测试需要分别提取公钥和验证 /usr/local/tongsuo/bin/openssl x509 -pubkey -in yourdomain_name.pem -noout pubkey.pem # 创建一个测试文件 echo test test.txt # 使用SM3进行摘要示例具体签名验证命令请参考Tongsuo文档注意Tongsuo的openssl命令参数可能与系统自带的略有不同特别是国密相关操作。务必使用/usr/local/tongsuo/bin/openssl并查阅其官方文档获取准确的国密证书和密钥操作命令。4.3 常见问题速查与解决方案表问题现象可能原因解决方案Nginx启动失败nginx: [emerg] SSL_CTX_use_PrivateKey_filefailed1. 私钥文件路径错误或不存在。2. 私钥文件格式不正确如密码保护。3. 私钥与证书不匹配。1. 检查ssl_certificate_key路径。2. 确认私钥为PKCS#8格式的PEM文件无密码。用openssl ec检查。3. 使用openssl工具验证证书和私钥是否配对。浏览器访问显示“不安全”1. 证书链不完整缺少中间CA。2. 客户端未信任国密根CA。3. 访问的域名与证书域名不符。1. 确保Nginx使用*_chain.pem文件。2. 在客户端安装对应的国密根证书。3. 检查证书的SAN主题备用名称是否包含当前域名。360浏览器提示“ERR_SSL_VERSION_OR_CIPHER_MISMATCH”1. Nginx未正确配置国密密码套件。2. Tongsuo编译时未启用国密SSL。3. 防火墙/安全组阻止了443端口。1. 核对ssl_ciphers配置确保包含ECC-SM2-WITH-SM4-SM3。2. 重新编译Tongsuo确保enable-ntls已开启。3. 检查服务器和云平台安全组规则。Chrome/Firefox可访问360浏览器无法访问360浏览器尝试使用国密套件失败且未成功回退到国际套件。检查Nginx配置确保国际套件如ECDHE-RSA-AES256-GCM-SHA384也正确列出在ssl_ciphers中并且ssl_prefer_server_ciphers设置为on让服务器优先选择国密。同时确认服务器证书是RSASM2双证书还是仅SM2证书。仅SM2时非国密浏览器必然失败这是正常情况。性能问题或连接缓慢1. 未启用SSL会话复用。2. 密钥交换算法效率问题。1. 在Nginx配置中优化ssl_session_cache和ssl_session_timeout。2. SM2算法在相同安全强度下计算效率通常优于RSA但首次握手仍有一定开销。确保服务器有足够计算资源。5. 高级配置与优化建议当基础功能跑通后我们可以考虑一些优化和增强配置让服务更稳定、更安全。5.1 实现国密与国际算法的自适应在生产环境中我们通常希望服务器能同时支持国密浏览器和国际标准浏览器。这需要服务器部署双证书一个SM2证书一个RSA/ECC证书。但本文基于阿里云单SM2证书的配置通过巧妙的密码套件配置也能实现一定程度的“协议级自适应”。我们的配置ssl_ciphers ECC-SM2-WITH-SM4-SM3:ECDHE-RSA-AES128-GCM-SHA256:...已经做了这件事。其工作原理是在TLS握手阶段客户端会发送它支持的密码套件列表服务器从这个列表和自身配置的ssl_ciphers列表中选择第一个双方都支持的套件。如果客户端如360浏览器支持ECC-SM2-WITH-SM4-SM3那么双方就使用国密套件建立连接。如果客户端如Chrome不支持国密套件但支持ECDHE-RSA-AES128-GCM-SHA256那么就会回退到使用这个国际套件。但是这里有一个关键前提使用国际套件时需要RSA/ECC证书和私钥来进行密钥交换和签名。如果你只有SM2证书那么握手会在证书验证阶段失败。这就是为什么Chrome访问仅配置SM2证书的站点会失败的原因。因此真正的双栈自适应需要你在Nginx中配置两套ssl_certificate和ssl_certificate_key这需要Nginx版本和Tongsuo库支持更高级的配置如ssl_certificate指令支持多个证书。目前更常见的生产实践是通过两个不同的server块监听同一个端口利用ssl_preread模块在TCP层根据客户端Hello信息分流到不同的上游分别处理国密和非国密流量。这涉及更复杂的Nginx流模块配置超出了本文基础指南的范围但这是构建全兼容HTTPS服务的方向。5.2 性能调优与安全加固启用OCSP Stapling在线证书状态协议装订可以加快证书验证速度并提升隐私。需要在Nginx配置中指定OCSP响应文件。首先获取OCSP响应器地址通常来自证书提供商然后配置ssl_stapling on; ssl_stapling_verify on; # 需要配置resolver并指向你的OCSP响应器URL请替换为实际地址 # 注意国密证书的OCSP服务可能由国内CA提供地址需咨询CA。 resolver 8.8.8.8 valid300s; resolver_timeout 5s;调整SSL会话缓存我们已经配置了ssl_session_cache可以根据并发连接数调整其大小。10m大约可以存储80000个会话。禁用不安全的协议和套件确保ssl_protocols中已禁用SSLv2和SSLv3。在ssl_ciphers列表中应避免包含已知不安全的套件如那些使用RC4、MD5或DES的套件。我们配置的套件已经是较安全的现代套件。定期更新与监控关注Tongsuo和Nginx的安全公告定期更新版本以修复漏洞。使用日志监控工具关注Nginx错误日志error.log中与SSL相关的错误。5.3 后续维护与扩展思考部署成功只是开始。在长期运维中你还需要考虑证书续期国密证书也有有效期通常1年。阿里云证书服务支持自动续期但续期后你需要将新的证书文件和私钥如果重新生成更新到服务器并重载Nginx配置nginx -s reload。建议建立证书到期提醒机制。多服务器部署如果你有多台后端应用服务器Nginx可以作为国密HTTPS终端然后通过HTTP或自定义加密协议与后端通信实现负载均衡和安全隔离。国密算法更深层次的应用除了HTTPS国密算法SM2/SM3/SM4还可以用于API签名、数据加密存储、数据库连接加密等场景。Tongsuo库也提供了相应的编程接口供开发者在应用程序中直接调用。回过头看从看到“国密证书”要求时的茫然到最终在360浏览器里看到绿色安全锁的成就感这个过程是对技术细节耐心打磨的典型写照。最大的体会是国密改造并非简单的证书替换而是一套从底层密码库到上层应用配置的完整技术栈切换。其中证书链的完整性、Nginx与国密密码库的正确链接、以及密码套件的精准配置是三个最关键的“阀门”任何一个没拧紧都会导致整个系统无法正常工作。建议在正式上线前务必在测试环境中完成全链路的兼容性测试覆盖所有需要支持的客户端类型。这份指南里的每一个步骤和坑点都源于真实的部署经历希望能为你扫清障碍顺利驶入国密合规的快车道。