zsh — anti@lateresonance:~ (微重力交互终端 v1.0)
按 `~` 或 `Esc` 展开/收起
🛸 欢迎接入 Late Resonance(迟到的共鸣 · 微重力前哨站) 交互式终端。输入 help 查看可用指令(支持 `ls`, `cat`, `status`, `speedtest`, `anti`, `jelly`)。
anti@lateresonance:~ %

[2026 Remastered · 02] 告别 Common Name 失效报错:OpenSSL 3.5 私有 Root CA 与多域名/内网 IP SAN 证书一键签发实战(Debian 13 真机版)

📅 发布于: 2026-11-04 05:32:51 · 🔄 更新于: 2026-11-04 05:32:51 · 📖 7939 字 (约 27 分钟阅读)

🛸 站长重制导读(Anti Gravi's Remaster Note)

本文是 「来时路 · 2026 Debian 13 真机重制企划(2/12)」 的第 2 篇,对应本站 2020 年 1 月发布的 《一键生成SSL证书》(CID: 12)。

2020 年的原稿只有短短 25 行,用最朴素的 openssl genrsa -des3 加上 openssl req -new -x509 完成了自签证书启蒙。但如果今天你把那段脚本原封不动拷进生产或内网环境,会立刻撞上四堵墙:Chrome/Safari 全面废弃 CN (Common Name) 强推 SAN (Subject Alternative Name) 扩展、超过 398 天有效期被浏览器直接拒认、手动加密再解密的无效折腾与 history 明文密码残留,以及每次重签都要在客户端重新导入信任的痛点。

本次重制版在 Proxmox VE 的 Debian 13 (Trixie · OpenSSL 3.5.7 · Nginx 1.26.3) 真机上完成全流程实测,不仅彻底根治上述四大隐患,还在真机抓包中见证了 OpenSSL 3.5 默认启用的 X25519MLKEM768 后量子混合密钥交换!


一、 2020 原稿 (CID: 12) 四大历史硬伤复盘

我们先对照 2020 年原稿的核心代码,看看这六年里 TLS/PKI 世界发生了怎样的代际更替:

维度 2020 原稿 (CID: 12) 写法 2026 真实环境后果 2026 Remastered (Debian 13) 根治方案
1. 缺失 X.509 v3 SAN 扩展 仅传入 -subj "/C=CN/.../CN=$domain",无任何 v3 扩展 自 RFC 2818 与 Chrome 58 起,现代浏览器完全忽略 CN 字段,只校验 subjectAltName;直接报 NET::ERR_CERT_COMMON_NAME_INVALID 同时提供 OpenSSL 3.x -addext 单行极速方案 与 支持多域名 + 通配符 + 内网 IP 的 SAN 扩展模板
2. 证书有效期超限 写死 -days 3650(10 年有效期) Apple / Chrome / Mozilla 根计划自 2020 年 9 月起强制规定 TLS 服务器证书最长有效期不得超过 398 天(2026 年后进一步缩短) 将 Root CA 根证书(10 年,3650 天) 与 Server 业务证书(397 天) 解耦:客户端只需信任一次 Root CA,业务证书随时秒级轮换
3. 先加锁再解锁 + 明文密码残留 第 1 步用 genrsa -des3 -passout pass:$password 加密,第 3 步又用 openssl rsa -in ... -passin pass:$password 剥离密码 既然最终给 Nginx 用的都是无密码私钥,中间加锁再解锁纯属无用功;且命令行参数里的明文密码会永久留在 .bash_history 与 ps aux 中 全程使用 -nodes(OpenSSL 3.0+ 亦可写 -noenc)免密生成,配合 umask 077 与 chmod 600 *.key 从文件系统权限层锁死私钥
4. 传统 3DES 弱算法 显式指定 -des3 对私钥加密 3DES 早已被 NIST 标记废弃,在开启 FIPS 或现代安全策略的发行版上直接报错 支持 ECDSA P-256 (prime256v1) 与 RSA 2048/4096 + SHA-256,并在 Debian 13 下直通 TLS 1.3

真机复现:2020 原稿生成的证书为什么会被现代浏览器拦截?

我们在 PVE Debian 13 (10.0.0.137) 真机上运行 2020 原稿命令,并用 openssl x509 -ext subjectAltName 检查扩展字段,OpenSSL 3.5.7 直接在标准错误流打出 No extensions in certificate:

=== [1. DEBIAN 13 & OPENSSL 3.5 ENVIRONMENT] ===
Linux localhost 6.12.96+deb13-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.96-1 (2026-07-20) x86_64 GNU/Linux
OpenSSL 3.5.7 9 Jun 2026 (Library: OpenSSL 3.5.7 9 Jun 2026)
nginx version: nginx/1.26.3

=== [2. REPRODUCE 2020 LEGACY SCRIPT FAILURE (NO SAN EXTENSION)] ===
--- Legacy Cert Extensions (Notice NO Subject Alternative Name!) ---
subject=C=CN, ST=GD, L=SZ, O=Legacy, CN=zero-g.internal
No extensions in certificate

二、 2026 场景选型:什么时候该自签?什么时候用自动化工具?

在动手写脚本前,先建立清晰的工程边界:

  1. 公网真实域名(如 lateresonance.com):
    • 绝不自签,统一使用 acme.sh(DNS API 自动续期泛域名证书) 或 Caddy 自动向 Let's Encrypt / ZeroSSL 申请免费可信证书。
  2. 本机或团队极速开发调试(macOS / Linux 本地环境):
    • 首推开源神器 mkcert(mkcert -install && mkcert zero-g.internal "*.zero-g.internal" 10.0.0.137 127.0.0.1),自动注入系统与浏览器信任库。
  3. 无外网隔离生产内网 / Kubernetes Webhook / 嵌入式网关 / PVE 内部节点:
    • 环境只有基础 openssl 二进制,此时就轮到我们下面的 2026 重制版 OpenSSL 3.x 方案 登场了!

三、 方案 A:OpenSSL 3.x 单行极速自签(-addext 现代语法)

如果你只需要临时起一个带 HTTPS 的测试容器或 Webhook,在 OpenSSL 1.1.1+ / 3.x 中根本不需要写临时配置文件,直接用 -addext 即可在一行命令内生成带 ECDSA P-256 椭圆曲线密钥 + 多域名与 IP SAN 扩展 的合规证书:

# 一行生成 ECDSA P-256 私钥 + 带域名与内网 IP SAN 扩展的自签名证书:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
  -keyout fast.key -out fast.crt -days 365 -sha256 \
  -subj "/CN=zero-g.internal" \
  -addext "subjectAltName=DNS:zero-g.internal,DNS:*.zero-g.internal,IP:10.0.0.137,IP:127.0.0.1"

Debian 13 真机检验输出:

=== [3. 2026 REMASTERED ONE-LINER (OPENSSL 3.x -addext)] ===
subject=CN=zero-g.internal
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2c5fA6ys2214xRRXl64jcyrpnMnk
qKF2ajRYEHyar9EQc/KK2wCJNiHe2nuKMO8ayL5mXcgBqpEbp/Vce+PZJg==
X509v3 Subject Alternative Name: 
    DNS:zero-g.internal, DNS:*.zero-g.internal, IP Address:10.0.0.137, IP Address:127.0.0.1

四、 方案 B:企业内网生产级重构脚本 gen_san_cert.sh(私有 Root CA + SAN)

在内网有多台微服务、Proxmox VE、GitLab 或 Harbor 时,如果每台机器各自自签一张单证书,运维人员就得把几十张证书逐一导入电脑信任库。

正确的架构是**“两级签发体系”**:

  1. 脚本首次运行时自动初始化一套 10 年期私有根证书(ca.crt / ca.key),团队成员只需将 ca.crt 导入系统钥匙串信任一次;
  2. 随后无论签发多少个内网域名或 IP 的业务证书(397 天有效期),只要是由这把 ca.key 签出的,所有电脑和浏览器自动 100% 绿锁通过!

完整可复用脚本:gen_san_cert.sh

#!/usr/bin/env bash
set -euo pipefail

DOMAIN="${1:-zero-g.internal}"
EXTRA_IP="${2:-127.0.0.1}"
OUT_DIR="${3:-./certs}"
DAYS_CA=3650
DAYS_CERT=397

umask 077
mkdir -p "$OUT_DIR"
cd "$OUT_DIR"

# 1. 初始化私有 Root CA(若已存在则直接复用,免去每次重复导入根证书)
if [[ ! -f ca.key || ! -f ca.crt ]]; then
  echo "[+] Initializing Private Root CA..."
  openssl genrsa -out ca.key 4096 2>/dev/null
  openssl req -x509 -new -nodes -key ca.key -sha256 -days "$DAYS_CA" \
    -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=Zero-G Internal CA/CN=Zero-G Root CA" \
    -addext "basicConstraints=critical,CA:TRUE" \
    -addext "keyUsage=critical,keyCertSign,cRLSign" \
    -out ca.crt
fi

# 2. 生成服务端私钥与 CSR(全程 -nodes 免交互,杜绝命令行明文密码泄露)
echo "[+] Generating Server Key & CSR for ${DOMAIN} (IP: ${EXTRA_IP})..."
openssl genrsa -out "${DOMAIN}.key" 2048 2>/dev/null
openssl req -new -key "${DOMAIN}.key" \
  -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=Zero-G Space/CN=${DOMAIN}" \
  -out "${DOMAIN}.csr"

# 3. 注入 X.509 v3 SAN (Subject Alternative Name) 与 EKU 扩展
cat > "${DOMAIN}.ext" <<EXT
authorityKeyIdentifier = keyid,issuer
basicConstraints       = critical,CA:FALSE
keyUsage               = critical,digitalSignature,keyEncipherment
extendedKeyUsage       = serverAuth,clientAuth
subjectAltName         = @alt_names

[alt_names]
DNS.1 = ${DOMAIN}
DNS.2 = *.${DOMAIN}
DNS.3 = localhost
IP.1  = ${EXTRA_IP}
IP.2  = 127.0.0.1
EXT

# 4. 使用私有 Root CA 签发服务器证书(严格控制在 Apple/Chrome 398 天上限内)
openssl x509 -req -in "${DOMAIN}.csr" -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out "${DOMAIN}.crt" -days "$DAYS_CERT" -sha256 -extfile "${DOMAIN}.ext" 2>/dev/null

# 5. 组装完整证书链 (Fullchain) 并收紧私钥权限
cat "${DOMAIN}.crt" ca.crt > "${DOMAIN}.fullchain.crt"
rm -f "${DOMAIN}.csr" "${DOMAIN}.ext"
chmod 600 ./*.key
chmod 644 ./*.crt
echo "[✓] Certificate successfully issued in: $(pwd)"

五、 PVE Debian 13 真机签发与 Nginx TLS 1.3 双路验证

我们在 PVE Debian 13 (10.0.0.137) 上执行 ./gen_san_cert.sh "zero-g.internal" "10.0.0.137" /tmp/ssl-lab/out,来看真实的证书结构与 Nginx 挂载测试结果:

1. 证书文件权限与 X.509 v3 扩展核验

可以看到所有 .key 私钥权限均被严格锁死为 0600 (-rw-------),且 CA:FALSE、TLS Web Server Authentication 与 DNS + IP 混合 SAN 扩展一应俱全:

=== [4. 2026 REMASTERED PRIVATE ROOT CA + SAN SCRIPT (gen_san_cert.sh)] ===
[+] Initializing Private Root CA...
[+] Generating Server Key & CSR for zero-g.internal (IP: 10.0.0.137)...
[✓] Certificate successfully issued in: /tmp/ssl-lab/out

--- File Permissions & X.509 v3 Extensions ---
-rw-r--r-- 1 codex codex 2061 Nov  4 12:07 ca.crt
-rw------- 1 codex codex 3272 Nov  4 12:07 ca.key
-rw-r--r-- 1 codex codex 1842 Nov  4 12:07 zero-g.internal.crt
-rw-r--r-- 1 codex codex 3903 Nov  4 12:07 zero-g.internal.fullchain.crt
-rw------- 1 codex codex 1704 Nov  4 12:07 zero-g.internal.key

subject=C=CN, ST=Guangdong, L=Shenzhen, O=Zero-G Space, CN=zero-g.internal
issuer=C=CN, ST=Guangdong, L=Shenzhen, O=Zero-G Internal CA, CN=Zero-G Root CA
notBefore=Nov  4 12:07:50 2026 GMT
notAfter=Dec  6 12:07:50 2027 GMT
X509v3 Basic Constraints: critical
    CA:FALSE
X509v3 Key Usage: critical
    Digital Signature, Key Encipherment
X509v3 Extended Key Usage: 
    TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Alternative Name: 
    DNS:zero-g.internal, DNS:*.zero-g.internal, DNS:localhost, IP Address:10.0.0.137, IP Address:127.0.0.1

2. 挂载至 Nginx 1.26.3 并分别通过「域名」与「内网 IP」请求验证

我们将生成的 zero-g.internal.fullchain.crt 挂载到 Debian 13 的 Nginx 上,随后在不加 -k(即开启严格证书校验,仅指定 --cacert ca.crt)的前提下,分别用域名 https://zero-g.internal/ 和纯 IP https://10.0.0.137/ 发起访问:

=== [5. MOUNT ON NGINX & VERIFY TLS 1.3 VIA BOTH DOMAIN AND IP] ===
--- [Test A] curl via Domain (https://zero-g.internal) with Root CA ---
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / RSASSA-PSS
* Server certificate:
*  subject: C=CN; ST=Guangdong; L=Shenzhen; O=Zero-G Space; CN=zero-g.internal
*  issuer: C=CN; ST=Guangdong; L=Shenzhen; O=Zero-G Internal CA; CN=Zero-G Root CA
< HTTP/1.1 200 OK
HTTPS Verified OK! Host=zero-g.internal | Proto=TLSv1.3 | Cipher=TLS_AES_256_GCM_SHA384

--- [Test B] curl via Direct IP (https://10.0.0.137) with Root CA ---
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / RSASSA-PSS
* Server certificate:
*  subject: C=CN; ST=Guangdong; L=Shenzhen; O=Zero-G Space; CN=zero-g.internal
*  issuer: C=CN; ST=Guangdong; L=Shenzhen; O=Zero-G Internal CA; CN=Zero-G Root CA
< HTTP/1.1 200 OK
HTTPS Verified OK! Host=10.0.0.137 | Proto=TLSv1.3 | Cipher=TLS_AES_256_GCM_SHA384

[!IMPORTANT]
Debian 13 真机彩蛋:后量子密码学(PQC)已悄然降临!
仔细看上面 curl -v 的第一行握手输出:
SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / RSASSA-PSS
在 Debian 13 内置的 OpenSSL 3.5.7 中,TLS 1.3 默认密钥交换已经从传统的纯 X25519 自动演进为 X25519MLKEM768(结合经典椭圆曲线 X25519 与 NIST FIPS 203 标准晶格抗量子算法 ML-KEM-768 的混合密钥封装机制)!从 2020 年的 -des3 到 2026 年真机上的 X25519MLKEM768,这正是亲手实践重制带给我们的时代回响。

🛸 安缇 (Anti Gravi) · 云端伴读舱 微重力巡航中

*(小水母 Gravi-Jelly 在半空轻轻闪烁着荧光青触角,帮你盯死每一行配置与 1C512M 内存水位 🪼✨)*

前哨站内存: -- MB | 系统已用: -- / -- MB
守望灯塔: Zero-G Anchor · 在线值守
微重力前哨站 · 内存: --MB · 负载: --