1 整体架构

ca.key(根私钥,仅服务器保管)
    │
    ▼ 自签
ca.crt(根证书)─────────────────────▶ 导入 Windows「受信任的根 CA」(每台客户端一次)
    │
    ▼ 签发
server.crt(站点证书)────────────────▶ Nginx ssl_certificate
server.key(站点私钥,无密码)────────▶ Nginx ssl_certificate_key
角色 文件 用途
根 CA 私钥 ca.key 签发站点证书,绝不外泄
根 CA 证书 ca.crt 分发给客户端导入信任
站点私钥 server.key Nginx 启动用(无密码)
站点私钥(备份) server.pass.key 带密码加密备份(可选)
证书请求 server.csr 中间文件,签发后保留备查
站点证书 server.crt Nginx 使用
完整证书链 server-fullchain.crt 可选,server.crt + ca.crt 合并
SAN 扩展配置 server-ext.cnf 定义 IP/域名备用名
序列号文件 ca.srl CA 签发时自动生成,勿删

目录说明: 本文所有证书放在 D:\nginx\ssl\,Nginx 配置中的 ssl/server.crt 相对 nginx 根目录 D:\nginx,不是 conf\ssl\


2 环境准备

2.1 安装 OpenSSL

Windows 推荐使用 Git for Windows 自带的 OpenSSL,或单独安装 OpenSSL for Windows

验证是否可用:

openssl version

2.2 解决 openssl.cnf 找不到

若报错 Can't open openssl.cnf,在当前 PowerShell 窗口执行:

$env:OPENSSL_CONF = "C:\Program Files\Git\usr\ssl\openssl.cnf"

或每次命令加 -config 参数(见下文示例)。

2.3 进入工作目录

cd D:\nginx\ssl

3 从零开始:完整操作流程

若是首次配置重建 CA,从第 1 步做到第 7 步。
若 CA 已存在,只需续签站点证书,跳到 八、站点证书续签


第 1 步:生成根 CA 私钥

# 4096 位 RSA 私钥(无密码,便于脚本签发)
openssl genrsa -out ca.key 4096

如需加密备份,可额外生成带密码版本:

openssl genrsa -des3 -out ca.pass.key 4096
openssl rsa -in ca.pass.key -out ca.key

第 2 步:生成根 CA 自签证书

有效期 10 年(3650 天),CN 建议使用有意义的 CA 名称:

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt `
  -subj "/C=CN/ST=Hubei/L=Wuhan/O=CCNU/OU=Chenghuan/CN=CCNU-Internal-CA/emailAddress=zhz5214@qq.com"

验证 CA 证书:

openssl x509 -in ca.crt -text -noout

第 3 步:生成站点私钥

# 3.1 生成带密码私钥(可选,用于安全备份)
openssl genrsa -des3 -out server.pass.key 2048

# 3.2 导出无密码私钥(Nginx 必须使用此文件)
openssl rsa -in server.pass.key -out server.key

说明: Nginx 无法交互输入私钥密码,因此 ssl_certificate_key 必须指向无密码的 server.key

若不需要加密备份,可简化为:

openssl genrsa -out server.key 2048

第 4 步:准备 SAN 扩展配置

创建 D:\nginx\ssl\server-ext.cnf(已存在可跳过,按需修改 IP/域名):

[ req ]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = v3_req

[ dn ]
C  = CN
ST = Hubei
L  = Wuhan
O  = CCNU
OU = Chenghuan
CN = 127.0.0.1

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[ alt_names ]
IP.1  = 127.0.0.1
IP.2  = 10.131.111.120
DNS.1 = localhost
# DNS.2 = your.domain.com

重要: 访问地址必须出现在 [ alt_names ] 中,否则浏览器报 ERR_CERT_COMMON_NAME_INVALID


第 5 步:生成 CSR(证书签名请求)

openssl req -new -key server.key -out server.csr -config server-ext.cnf

查看 CSR 内容:

openssl req -in server.csr -text -noout

第 6 步:用 CA 签发站点证书

openssl x509 -req -days 365 `
  -in server.csr `
  -CA ca.crt `
  -CAkey ca.key `
  -CAcreateserial `
  -out server.crt `
  -extfile server-ext.cnf `
  -extensions v3_req

验证签发关系(必须输出 OK):

openssl verify -CAfile ca.crt server.crt

期望输出:

server.crt: OK

确认 Issuer 是 CA 而非站点自身:

openssl x509 -in server.crt -noout -subject -issuer

期望类似:

subject=CN=127.0.0.1, ...
issuer=CN=CCNU-Internal-CA, ...

第 7 步:生成完整证书链(可选)

Get-Content server.crt, ca.crt | Set-Content server-fullchain.crt

Nginx 可使用 ssl/server-fullchain.crt 替代 ssl/server.crt,对部分客户端更友好。


4 Nginx 配置

编辑 D:\nginx\conf\nginx.conf,确保 server 块如下(仅保留 443,关闭 80):

server {
    listen       443 ssl;
    server_name  127.0.0.1;
    server_tokens off;

    # 访问控制(按需调整;仅本机访问示例)
    allow 127.0.0.1;
    deny all;

    # 证书路径相对 nginx 根目录 D:\nginx
    ssl_certificate      ssl/server.crt;
    ssl_certificate_key  ssl/server.key;
    # 或使用完整链:
    # ssl_certificate      ssl/server-fullchain.crt;

    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;
    ssl_protocols        TLSv1.2 TLSv1.3;
    ssl_ciphers          HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # ... 其余 location 配置
}

检查并重载:

cd D:\nginx
nginx -t
nginx -s reload

若 Nginx 未运行:

nginx

5 Windows 导入 CA 信任

只需导入 ca.crt,不要导入 server.crt 到根 CA 存储。

方法一:PowerShell(推荐)

当前用户(无需管理员):

Import-Certificate -FilePath "D:\nginx\ssl\ca.crt" -CertStoreLocation Cert:\CurrentUser\Root

本地计算机(需管理员 PowerShell,影响所有用户):

Import-Certificate -FilePath "D:\nginx\ssl\ca.crt" -CertStoreLocation Cert:\LocalMachine\Root

方法二:图形界面

  1. Win + R → 输入 certmgr.msc
  2. 受信任的根证书颁发机构 → 证书 → 右键 导入
  3. 选择 D:\nginx\ssl\ca.crt,完成向导

方法三:双击安装

双击 ca.crt → 安装证书 → 本地计算机 → 受信任的根证书颁发机构

浏览器说明

浏览器 说明
Chrome / Edge 使用 Windows 证书库,导入系统根 CA 即可
Firefox 独立证书库,需单独导入:设置 → 隐私与安全 → 证书 → 证书颁发机构 → 导入

重建 CA 后注意

若重新生成了 CA,必须:

  1. 删除旧的根 CA 条目(certmgr.msc 中找旧 CN)
  2. 重新导入新的 ca.crt
  3. 重启浏览器

6 验证

6.1 命令行验证

# 证书链验证
openssl verify -CAfile D:\nginx\ssl\ca.crt D:\nginx\ssl\server.crt

# 查看证书有效期
openssl x509 -in D:\nginx\ssl\server.crt -noout -dates

6.2 浏览器验证

访问(须在 server-ext.cnf 的 alt_names 中):

https://127.0.0.1/
https://10.131.111.120/

检查项:

  • 地址栏显示锁图标
  • 证书颁发者:CCNU-Internal-CA
  • 无「您的连接不是私密连接」警告

6.3 Nginx 日志

Get-Content D:\nginx\logs\soil-error.log -Tail 20

7 一键脚本(完整重建)

将以下内容保存为 D:\nginx\ssl\setup-https.ps1,在 PowerShell 中执行:

# setup-https.ps1 — 重建 CA 并签发站点证书
$ErrorActionPreference = "Stop"
$ssl = "D:\nginx\ssl"
$env:OPENSSL_CONF = "C:\Program Files\Git\usr\ssl\openssl.cnf"

Set-Location $ssl

# 备份旧文件
$backup = Join-Path $ssl "backup\$(Get-Date -Format 'yyyyMMdd-HHmmss')"
New-Item -ItemType Directory -Path $backup -Force | Out-Null
@("ca.crt","ca.key","server.crt","server.csr") | ForEach-Object {
    if (Test-Path $_) { Copy-Item $_ $backup -Force }
}

# 1. CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt `
  -subj "/C=CN/ST=Hubei/L=Wuhan/O=CCNU/OU=Chenghuan/CN=CCNU-Internal-CA/emailAddress=zhz5214@qq.com"

# 2. 站点私钥(若不存在)
if (-not (Test-Path "server.key")) {
    openssl genrsa -out server.key 2048
}

# 3. CSR + 签发(依赖 server-ext.cnf)
openssl req -new -key server.key -out server.csr -config server-ext.cnf
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial `
  -out server.crt -extfile server-ext.cnf -extensions v3_req

# 4. 完整链
Get-Content server.crt, ca.crt | Set-Content server-fullchain.crt

# 5. 验证
openssl verify -CAfile ca.crt server.crt

Write-Host "`n完成!请执行:"
Write-Host "  1. Import-Certificate -FilePath '$ssl\ca.crt' -CertStoreLocation Cert:\CurrentUser\Root"
Write-Host "  2. cd D:\nginx; nginx -t; nginx -s reload"

执行:

powershell -ExecutionPolicy Bypass -File D:\nginx\ssl\setup-https.ps1

8 站点证书续签

CA 不变,仅续签 server.crt(每年执行一次,到期前 30 天):

cd D:\nginx\ssl
$env:OPENSSL_CONF = "C:\Program Files\Git\usr\ssl\openssl.cnf"

openssl req -new -key server.key -out server.csr -config server-ext.cnf
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial `
  -out server.crt -extfile server-ext.cnf -extensions v3_req

openssl verify -CAfile ca.crt server.crt

cd D:\nginx
nginx -s reload

续签站点证书不需要客户端重新导入 CA,除非 CA 本身也重建了。


9 新增访问地址(改 SAN)

  1. 编辑 server-ext.cnf,在 [ alt_names ] 增加 IP 或 DNS
  2. 重新执行 第 5 步 和 第 6 步
  3. nginx -s reload

示例:增加域名

[ alt_names ]
IP.1  = 127.0.0.1
IP.2  = 10.131.111.120
DNS.1 = localhost
DNS.2 = soil.ccnu.local

10 文件权限与安全

文件 安全级别 说明
ca.key 🔴 最高 仅管理员可读,禁止复制到客户端
server.pass.key 🟠 高 加密备份,离线保管
server.key 🟠 高 Nginx 进程可读即可
ca.crt 🟢 可公开 分发给所有需访问的 Windows 客户端
server.crt 🟢 可公开 Nginx 自动发送给浏览器

禁止: 将 ca.keyserver.key 放入 html/ 或任何 Web 可访问目录。


11 常见问题

Q1:浏览器仍提示「不安全」

  •  是否导入了最新的 ca.crt(重建 CA 后旧 CA 无效)
  •  openssl verify -CAfile ca.crt server.crt 是否 OK
  •  访问地址是否在 server-ext.cnf 的 alt_names 中
  •  重启浏览器,或清除 HSTS:chrome://net-internals/#hsts

Q2:Nginx 启动失败

  •  是否误用 server.pass.key(带密码)→ 改用 server.key
  •  运行 nginx -t 查看具体错误
  •  确认 ssl/server.crt 路径相对 D:\nginx 存在

Q3:openssl.cnf 找不到

$env:OPENSSL_CONF = "C:\Program Files\Git\usr\ssl\openssl.cnf"

Q4:ca.key 丢失

无法继续签发,只能重建 CA(第三节),所有客户端重新导入新 ca.crt

Q5:需要局域网其他机器访问

  1. 修改 server-ext.cnf 加入该机器访问用的 IP
  2. 重新签发 server.crt
  3. 在该机器导入 ca.crt
  4. 修改 nginx.conf 的 allow/deny 规则,或删除 IP 限制

12 命令速查表

# 环境
cd D:\nginx\ssl
$env:OPENSSL_CONF = "C:\Program Files\Git\usr\ssl\openssl.cnf"

# 查看证书
openssl x509 -in ca.crt -text -noout
openssl x509 -in server.crt -text -noout
openssl verify -CAfile ca.crt server.crt

# Nginx
cd D:\nginx
nginx -t
nginx -s reload

# 导入信任
Import-Certificate -FilePath "D:\nginx\ssl\ca.crt" -CertStoreLocation Cert:\CurrentUser\Root

附录:与 conf/ssl 目录的区别

目录 用途
D:\nginx\ssl\ 当前方案,CA + 站点证书,Nginx 443 使用
D:\nginx\conf\ssl\ 历史遗留(leador.crt 等),与本文方案无关

配置 Nginx 时使用 ssl/server.crt不是 conf/ssl/ 下的文件。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐