公司动态
OpenSSL自签名HTTPS证书生成与Nginx配置指南
1. 为什么需要自签HTTPS证书在Web服务部署中HTTPS早已成为标配而非可选。但很多开发者在本地测试、内网服务或非生产环境部署时往往会遇到一个现实问题如何快速获得可用的HTTPS证书商业证书需要付费申请Lets Encrypt等免费方案又需要域名验证。这时自签名证书Self-Signed Certificate就成了最实用的解决方案。我最近在为一个金融类项目搭建测试环境时就遇到了这个典型场景。客户要求所有接口必须走HTTPS但测试服务器用的是内网IP无法通过常规CA验证。通过OpenSSL自签证书配合Nginx配置半小时就解决了问题。这种方案特别适合本地开发环境调试企业内部系统临时演示环境微服务间通信加密注意自签名证书浏览器会显示不安全警告这是正常现象。生产环境请务必使用可信CA颁发的证书。2. OpenSSL工具链准备2.1 安装验证OpenSSL大多数Linux系统已预装OpenSSL通过以下命令检查版本openssl version # 期望输出类似OpenSSL 1.1.1f 31 Mar 2020如果提示命令不存在则需要手动安装Ubuntu/Debian:sudo apt update sudo apt install opensslCentOS/RHEL:sudo yum install opensslmacOS自带但可能版本旧:brew install openssl2.2 关键文件说明执行证书生成操作前需要了解几个核心文件server.key- 私钥文件必须严格保密server.csr- 证书签名请求文件server.crt- 最终生成的证书文件server.pem- 有时用于合并证书链我习惯在/etc/nginx/ssl目录下管理这些文件sudo mkdir -p /etc/nginx/ssl cd /etc/nginx/ssl sudo chmod 700 /etc/nginx/ssl # 限制目录权限3. 证书生成全流程3.1 生成RSA私钥首先生成2048位的私钥安全与性能的平衡点openssl genrsa -out server.key 2048 # 如果想增加私钥安全性可以添加-aes256加密 # openssl genrsa -aes256 -out server.key 2048关键参数解析genrsa生成RSA密钥-out指定输出文件2048密钥长度1024已不安全4096性能开销大实测建议测试环境用2048位足够金融等高安全场景建议4096位。加密的私钥每次Nginx重启都需要输入密码自动化部署时需权衡。3.2 创建CSR文件CSRCertificate Signing Request包含申请者的公钥和身份信息openssl req -new -key server.key -out server.csr执行后会交互式询问信息典型输入示例Country Name (2 letter code) [AU]:CN State or Province Name (full name) [Some-State]:Beijing Locality Name (eg, city) []:Beijing Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyDev Inc Organizational Unit Name (eg, section) []:DevOps Common Name (e.g. server FQDN or YOUR name) []:test.example.com Email Address []:adminexample.com Please enter the following extra attributes A challenge password []: # 直接回车留空 An optional company name []: # 直接回车留空重点说明Common Name必须与最终访问的域名一致本地测试可用IP其他字段按需填写但不可全部为空生产环境建议所有字段规范填写3.3 生成自签名证书关键命令有效期设为365天openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt高级用法生成SAN证书支持多域名/IP需要额外配置文件san.cnf[req] distinguished_name req_distinguished_name req_extensions v3_req prompt no [req_distinguished_name] C CN ST Beijing L Beijing O MyDev Inc OU DevOps CN test.example.com [v3_req] keyUsage keyEncipherment, dataEncipherment extendedKeyUsage serverAuth subjectAltName alt_names [alt_names] DNS.1 test.example.com DNS.2 dev.example.com IP.1 192.168.1.100 IP.2 127.0.0.1生成命令变为openssl req -new -key server.key -out server.csr -config san.cnf openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -extensions v3_req -extfile san.cnf4. Nginx配置实战4.1 基础HTTPS配置在Nginx配置文件中添加server { listen 443 ssl; server_name test.example.com; ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; location / { root /var/www/html; index index.html; } }4.2 增强安全配置推荐的安全强化配置ssl_protocols TLSv1.2 TLSv1.3; # 禁用老旧协议 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; ssl_stapling off; # 自签名证书无法开启OCSP # 启用HSTS生产环境谨慎使用 add_header Strict-Transport-Security max-age63072000 always;4.3 HTTP强制跳转HTTPS在80端口配置中添加server { listen 80; server_name test.example.com; return 301 https://$host$request_uri; }5. 浏览器信任证书5.1 客户端安装证书虽然自签名证书不受公共CA信任但可以手动添加到系统信任库Windows双击.crt文件选择安装证书存储位置选本地计算机选择将所有证书放入下列存储浏览选择受信任的根证书颁发机构macOSsudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain server.crtLinuxChrome# 对于Debian系 sudo cp server.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates5.2 解决Chrome的NET::ERR_CERT_AUTHORITY_INVALID即使安装了证书Chrome可能仍显示警告。需要访问chrome://flags/#allow-insecure-localhost启用Allow invalid certificates for resources loaded from localhost6. 常见问题排查6.1 证书验证失败使用OpenSSL验证证书链openssl verify -CAfile server.crt server.crt典型错误及解决方案unable to get local issuer certificate→ 证书链不完整certificate has expired→ 重新生成证书hostname mismatch→ 检查CN和SAN配置6.2 Nginx报错排查查看Nginx错误日志tail -f /var/log/nginx/error.log常见错误SSL_CTX_use_PrivateKey_file: key values mismatch→ 证书密钥不匹配no ssl_certificate is defined→ 路径配置错误SSL routines:ssl_choose_client_version:unsupported protocol→ 协议配置问题7. 进阶技巧与优化7.1 证书自动续期脚本创建renew_ssl.sh#!/bin/bash cd /etc/nginx/ssl openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout server.key -out server.crt \ -subj /CCN/STBeijing/LBeijing/OMyDev Inc/OUIT/CNtest.example.com nginx -s reload添加到crontab每月1号凌晨3点执行0 3 1 * * /etc/nginx/ssl/renew_ssl.sh7.2 性能优化参数在高并发场景下调整ssl_buffer_size 4k; # 减少初始加密数据包大小 ssl_session_tickets on; # 启用会话票证 ssl_early_data on; # 启用0-RTTTLS 1.37.3 多域名配置方案单个Nginx实例支持多个证书server { listen 443 ssl; server_name api.example.com; ssl_certificate /path/to/api.crt; ssl_certificate_key /path/to/api.key; # ... } server { listen 443 ssl; server_name app.example.com; ssl_certificate /path/to/app.crt; ssl_certificate_key /path/to/app.key; # ... }8. 安全注意事项私钥保护设置严格的文件权限chmod 400 server.key禁止私钥上传到代码仓库考虑使用HSM硬件安全模块存储密钥证书生命周期管理记录每个证书的到期时间建立续期提醒机制废弃证书及时吊销虽然自签名无法全局吊销加密算法选择优先选择ECDSA over RSA使用SHA-256及以上哈希算法禁用SSLv3、TLS 1.0/1.1内网特别建议即使在内网也全链路HTTPS为所有内部服务分配唯一域名建立内部CA统一管理证书在实际操作中我发现很多团队容易忽视证书管理导致临时抱佛脚。建议将证书生成流程脚本化纳入DevOps自动化流程。对于需要团队共享的环境可以使用密码保护的PKCS#12格式打包证书openssl pkcs12 -export -out bundle.p12 -inkey server.key -in server.crt