# 用 OpenSSL 生成 CSR（RSA/ECDSA，含 SAN 多域名）

> 用一条 OpenSSL 命令生成私钥和证书签名请求（CSR），添加 subjectAltName 多个域名，选择 RSA 2048 或 ECDSA P-256，并检查 CSR。

Source: https://ssl.sh/zh/guides/generate-csr-openssl/
Last updated: 2026-11-10

一条 `openssl req -new -newkey` 命令就能同时生成私钥和证书签名请求（CSR），用 `-addext` 把 `example.com` 和 `www.example.com` 写进 SAN，检查无误后提交给 CA。

命令适用于 Linux、macOS、Windows 上的 OpenSSL 3.x，OpenSSL 1.1.1 参数不同的地方会单独说明。

## 前提条件

需要 OpenSSL 和证书要覆盖的完整域名清单。

- OpenSSL 3.x（`openssl version` 查看）。OpenSSL 1.1.1 把 `-noenc` 换成 `-nodes`；1.0.2 不支持 `-addext`，应该升级。
- 域名清单：访客会用到的每个域名，例如 `example.com` 和 `www.example.com`。
- 安全保存私钥的地方，最好直接在要使用证书的服务器上生成。

## 第一步：生成 ECDSA 私钥和 CSR

新证书默认推荐 ECDSA P-256。下面的命令同时生成私钥和 CSR，`-noenc` 表示私钥不加密码：

```bash
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -noenc \
  -keyout example.com.key -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
chmod 600 example.com.key
```

## 第二步（可选）：生成 RSA 私钥和 CSR

必须兼容老客户端时改用 RSA 2048，命令只换了密钥参数：

```bash
openssl req -new -newkey rsa:2048 -noenc \
  -keyout example.com.key -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
chmod 600 example.com.key
```

安全策略要求更长密钥时用 `rsa:3072`。通配符证书写 `DNS:*.example.com,DNS:example.com`。

## 第三步：域名多时用配置文件

SAN 很多或需要重复生成时，把信息写进配置文件：

```ini
# example.com.cnf
[req]
prompt = no
distinguished_name = dn
req_extensions = ext

[dn]
CN = example.com

[ext]
subjectAltName = DNS:example.com,DNS:www.example.com,DNS:api.example.com
```

```bash
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -noenc \
  -keyout example.com.key -out example.com.csr -config example.com.cnf
```

## 第四步：提交 CSR

把整个文件内容（包括 `-----BEGIN CERTIFICATE REQUEST-----` 和 `-----END CERTIFICATE REQUEST-----` 两行）粘贴到 CA 或云控制台的申请页面：

```bash
cat example.com.csr
```

`example.com.key` 留在服务器上，CA 不需要它。想用表单操作，[CSR 生成器](https://ssl.sh/zh/tools/csr-generator/) 在浏览器本地生成私钥和 CSR，私钥不会上传。

## 验证

提交前确认 CSR 的签名有效，主题和 SAN 里包含所有域名：

```bash
openssl req -in example.com.csr -noout -verify -subject
openssl req -in example.com.csr -noout -text | grep -A1 "Subject Alternative Name"
```

确认私钥和 CSR 是一对（两个哈希必须相同）：

```bash
openssl pkey -in example.com.key -pubout | openssl sha256
openssl req -in example.com.csr -noout -pubkey | openssl sha256
```

[CSR 解析](https://ssl.sh/zh/tools/csr-decoder/) 和 [私钥匹配检查](https://ssl.sh/zh/tools/key-matcher/) 能在浏览器里做同样的检查。证书装好后，用 [SSL 证书检查](https://ssl.sh/zh/tools/ssl-checker/) 或 `curl ssl.sh/example.com` 检查线上网站。

## 自动续期

CSR 是一次性的，续期就要重新生成。2026 年 3 月 15 日起公网证书最长 200 天，2027 年 3 月 15 日起 100 天，2029 年 3 月 15 日起 47 天，“生成 CSR、粘贴、等待、安装”的手动流程很快会变成每几周一次。能用 ACME 就让客户端生成密钥和 CSR：Certbot、acme.sh、lego 每次续期都会生成新私钥，不少商业 CA 也支持带 EAB 的 ACME。只能手动的，把第一到第四步写成脚本，并把域名加到 [ssl.sh 监控](https://ssl.sh/zh/monitor/)（开发中）。

## 常见问题排查

- **req: Unknown option or cipher: noenc**：用的是 OpenSSL 1.1.1，改用 `-nodes`。
- **CA 提示 CSR 没有 SAN 或域名不对**：`-addext` 漏了或写错了，解析 CSR 检查后重新生成。
- **装好证书后浏览器提示域名不匹配**：SAN 里漏了某个域名，见 [NET::ERR_CERT_COMMON_NAME_INVALID](https://ssl.sh/zh/errors/net-err-cert-common-name-invalid/)。
- **服务器报 key values mismatch**：证书是用另一个 CSR/私钥签发的，见 [nginx key values mismatch](https://ssl.sh/zh/errors/nginx-key-values-mismatch/)。
- **CA 拒绝密钥**：低于 2048 位的 RSA 和不受支持的曲线会被拒绝，用 P-256 或 RSA 2048 以上。
