OpenSSL自签名HTTPS证书生成与Nginx配置指南

📅 2026/7/31 11:38:10 👁️ 阅读次数 📝 编程学习
OpenSSL自签名HTTPS证书生成与Nginx配置指南

1. 为什么需要自签HTTPS证书?

在Web服务部署中,HTTPS早已成为标配而非可选。但很多开发者在本地测试、内网服务或非生产环境部署时,往往会遇到一个现实问题:如何快速获得可用的HTTPS证书?商业证书需要付费申请,Let's 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 openssl
  • CentOS/RHEL:
    sudo yum install openssl
  • macOS(自带但可能版本旧):
    brew install openssl

2.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文件

CSR(Certificate 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 []:admin@example.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.cnf

4. 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-age=63072000" 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

    1. 双击.crt文件
    2. 选择"安装证书"
    3. 存储位置选"本地计算机"
    4. 选择"将所有证书放入下列存储",浏览选择"受信任的根证书颁发机构"
  • macOS

    sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain server.crt
  • Linux(Chrome)

    # 对于Debian系 sudo cp server.crt /usr/local/share/ca-certificates/ sudo update-ca-certificates

5.2 解决Chrome的NET::ERR_CERT_AUTHORITY_INVALID

即使安装了证书,Chrome可能仍显示警告。需要:

  1. 访问chrome://flags/#allow-insecure-localhost
  2. 启用"Allow invalid certificates for resources loaded from localhost"

6. 常见问题排查

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 "/C=CN/ST=Beijing/L=Beijing/O=MyDev Inc/OU=IT/CN=test.example.com" nginx -s reload

添加到crontab(每月1号凌晨3点执行):

0 3 1 * * /etc/nginx/ssl/renew_ssl.sh

7.2 性能优化参数

在高并发场景下调整:

ssl_buffer_size 4k; # 减少初始加密数据包大小 ssl_session_tickets on; # 启用会话票证 ssl_early_data on; # 启用0-RTT(TLS 1.3)

7.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. 安全注意事项

  1. 私钥保护

    • 设置严格的文件权限:chmod 400 server.key
    • 禁止私钥上传到代码仓库
    • 考虑使用HSM(硬件安全模块)存储密钥
  2. 证书生命周期管理

    • 记录每个证书的到期时间
    • 建立续期提醒机制
    • 废弃证书及时吊销(虽然自签名无法全局吊销)
  3. 加密算法选择

    • 优先选择ECDSA over RSA
    • 使用SHA-256及以上哈希算法
    • 禁用SSLv3、TLS 1.0/1.1
  4. 内网特别建议

    • 即使在内网也全链路HTTPS
    • 为所有内部服务分配唯一域名
    • 建立内部CA统一管理证书

在实际操作中,我发现很多团队容易忽视证书管理,导致临时抱佛脚。建议将证书生成流程脚本化,纳入DevOps自动化流程。对于需要团队共享的环境,可以使用密码保护的PKCS#12格式打包证书:

openssl pkcs12 -export -out bundle.p12 -inkey server.key -in server.crt