在本地开发环境中为IP地址配置HTTPS服务是个常见需求,但很多人不知道如何为裸IP生成合法的SSL证书。本文将手把手教你用OpenSSL创建支持IP地址的SAN证书,并在Windows平台的Nginx上部署。
注意:自签名证书仅适用于开发和测试环境,生产环境请使用正规CA签发的证书。
传统SSL证书验证的是域名所有权,而IP地址无法通过常规的DNS验证。解决方案是使用主题备用名称(SAN)扩展,在X.509证书中明确声明支持的IP地址。
自签名证书意味着:
无论Linux还是Windows,都需要先安装OpenSSL:
bash复制# Ubuntu/Debian
sudo apt install openssl
# CentOS/RHEL
sudo yum install openssl
# Windows
# 下载Win64 OpenSSL安装包
# https://slproweb.com/products/Win32OpenSSL.html
ip-san.cnf文件是核心配置,解释每个关键参数:
ini复制[ req ]
default_bits = 2048 # RSA密钥长度,推荐2048位
distinguished_name = req_distinguished_name
req_extensions = req_ext # 启用扩展字段
prompt = no # 非交互模式
[ req_distinguished_name ]
countryName = CN # 国家代码(2字母)
stateOrProvinceName = Beijing # 省份
localityName = Beijing # 城市
organizationName = MyCompany # 组织名称
commonName = 192.168.1.100 # 必须与访问的IP一致
[ req_ext ]
subjectAltName = @alt_names # SAN扩展
[ alt_names ]
IP.1 = 192.168.1.100 # 主IP
# 可添加多个IP或域名
# IP.2 = 10.0.0.1
# DNS.1 = example.com
bash复制# 1. 生成私钥(保管好!)
openssl genrsa -out server.key 2048
# 2. 创建证书签名请求(CSR)
openssl req -new -key server.key -out server.csr -config ip-san.cnf
# 3. 自签名证书(有效期10年)
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt -extfile ip-san.cnf -extensions req_ext
# 4. 生成PFX格式(Windows导入用)
openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt -password pass:123456
安全提示:生产环境应将私钥密码设置为强密码,而非简单的"123456"
建议在Nginx目录下创建ssl子目录:
code复制C:\nginx\ssl\
├── server.crt
├── server.key
└── server.pfx
nginx复制server {
listen 443 ssl;
server_name 192.168.1.100; # 必须与证书CN一致
# 证书路径(使用正斜杠)
ssl_certificate C:/nginx/ssl/server.crt;
ssl_certificate_key C:/nginx/ssl/server.key;
# 安全协议配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# 性能优化
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
root html;
index index.html;
}
}
bash复制nginx -t # 测试配置
nginx -s reload # 重载配置
server.pfx文件启动导入向导powershell复制# 导入到个人存储
Import-PfxCertificate -FilePath C:\nginx\ssl\server.pfx -CertStoreLocation Cert:\LocalMachine\My -Password (ConvertTo-SecureString -String "123456" -AsPlainText -Force)
# 将证书设为受信任根(需管理员权限)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import("C:\nginx\ssl\server.crt")
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root","LocalMachine"
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()
| 错误类型 | 解决方案 |
|---|---|
| NET::ERR_CERT_AUTHORITY_INVALID | 将证书导入"受信任的根证书颁发机构" |
| NET::ERR_CERT_COMMON_NAME_INVALID | 检查CN和SAN是否包含访问的IP |
| 页面加载不安全内容 | 确保所有资源使用HTTPS链接 |
log复制# 错误:SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
# 原因:证书与私钥不匹配
# 解决:重新生成证书对
# 错误:no "ssl_certificate" is defined for the "listen ... ssl"
# 原因:证书路径错误
# 解决:检查路径是否存在空格或中文
bash复制openssl x509 -in server.crt -noout -dates
# 输出示例:
# notBefore=Jun 1 00:00:00 2023 GMT
# notAfter=May 29 00:00:00 2033 GMT
修改ip-san.cnf的[alt_names]部分:
ini复制IP.1 = 192.168.1.100
IP.2 = 10.0.0.1
DNS.1 = internal.example.com
bash复制# 生成ECC私钥
openssl ecparam -genkey -name prime256v1 -out ecc.key
# 生成CSR
openssl req -new -key ecc.key -out ecc.csr -config ip-san.cnf
# 自签名
openssl x509 -req -days 3650 -in ecc.csr -signkey ecc.key -out ecc.crt -extfile ip-san.cnf -extensions req_ext
创建renew_cert.sh:
bash复制#!/bin/bash
openssl x509 -x509toreq -in server.crt -signkey server.key -out server.csr
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server_new.crt -extfile ip-san.cnf -extensions req_ext
mv server_new.crt server.crt
我在实际部署中发现,Windows版Nginx对证书路径中的空格特别敏感,建议将证书存放在无空格路径(如C:\nginx\ssl)。另外,使用ECC证书可以显著提升TLS握手性能,特别是在树莓派等低功耗设备上。