本教程将向您展示如何使用 OpenSSL 为 Heroku 生成 CSR(证书签名请求),以及如何使用 Heroku CLI 上传已签发的证书。
Heroku 平台本身没有内置的 CSR 表单,因此请求文件和对应的私钥需要在平台外生成(在您的本地 Linux、macOS 或 Windows 计算机上,或任何安装了 OpenSSL 的 shell 环境中)。一旦证书颁发机构签发了证书,您需要将其与中间证书链合并,然后通过 heroku certs:add 上传。
您真的需要在 Heroku 上生成 CSR 吗?
对于大多数 Heroku 应用来说,答案是不需要。Heroku 的自动证书管理(Automated Certificate Management,ACM)会为应用上的每个自定义域名提供并自动续期免费的 Let’s Encrypt 证书,无需生成 CSR,也无需维护续期日程。ACM 适用于 Eco、Basic、Standard 和 Performance dyno。如果 ACM 符合您的使用场景,只需一条 CLI 命令即可启用:
heroku certs:auto:enable -a your-app-name
只有在以下情况之一适用时,才需要生成 CSR 并使用自行管理(第三方)证书:
- 您需要通配符证书。ACM 每个自定义域名只签发单域名的 Let’s Encrypt 证书,不支持 *.example.com 这样的通配符。
- 您需要OV或EV验证。ACM 仅支持 DV 验证。
- 您的政策或合同要求使用 Let’s Encrypt 之外的特定证书颁发机构。
- 您已拥有有效证书,希望在 Heroku 上重新部署而无需重新签发。
- 您需要多域名(SAN)证书,覆盖的主机名并非都在此 Heroku 应用上。
如果上述情况均不适用,请跳过 CSR 相关工作,直接使用 ACM。关于安装流程本身,请参阅我们的如何在 Heroku 上安装 SSL 证书指南。
生成 CSR 之前需要了解的 Heroku SSL 基础知识
有几项平台限制决定了 CSR 和私钥应有的形式:
- SNI 是默认方式。每个新应用都使用Heroku SSL,它依赖服务器名称指示(Server Name Indication),因此单个 Heroku 端点可以为多个使用各自证书的 HTTPS 主机名提供服务。旧版 SSL Endpoint 附加组件已于 2021 年弃用(2021 年 5 月 14 日起停止新配置;该产品于 2021 年 10 月 18 日正式停止使用),新应用不可用。
- 仅支持 RSA 密钥。Heroku 的 SSL 堆栈仅接受 RSA 私钥(2048 位或更大)。手动上传证书不支持 ECDSA 密钥,因此生成 CSR 时应使用 -newkey rsa:2048(如果您的策略要求更大的密钥,可使用 rsa:3072 或 rsa:4096)。
- 需要完整证书链 PEM 文件。Heroku 要求提供单个 PEM 文件,其中终端实体证书在前,中间 CA 证书链紧随其后拼接。仅包含叶证书的文件在上传时会被拒绝。
- 未加密的私钥。与证书一起上传的私钥不能设置口令保护。下方的 OpenSSL 命令使用 -nodes 参数,以明文 PEM 格式写出私钥。
- 自定义域名前置条件。在通过
heroku domains:add将自定义域名注册到应用,并指向对应的 *.herokudns.com DNS 目标之前,Heroku 不会绑定任何证书(无论是 ACM 还是手动证书)。
使用 OpenSSL 为 Heroku 生成 CSR
如果您已经生成了 CSR 并从证书颁发机构收到了已签发的证书,请直接跳转到将证书上传到 Heroku部分。为 Heroku 部署创建 CSR 有两种方式:
- 使用 SSL Dragon 的CSR 生成器:它会在您的浏览器中根据简短的表单同时生成 CSR 和匹配的 RSA 私钥,之后您只需在下单时粘贴 CSR。
- 自行使用 OpenSSL 生成 CSR,无论是在本地计算机上,还是在任何安装了 OpenSSL 的 shell 环境中。以下步骤将介绍这一流程。
步骤 1: 打开带有 OpenSSL 的 shell
OpenSSL 在所有近期的 Linux 发行版和 macOS 上都是自带的。在 Windows 上,需要先安装它(参见我们的在 Windows 上安装 OpenSSL指南),然后在 PowerShell 或命令提示符中运行命令。在任意一个您有写入权限的文件夹中打开终端: OpenSSL 会在此处以纯文本形式生成 CSR 和私钥文件,完成后您可以将它们从该机器上移走。
步骤 2: 运行 OpenSSL 命令
在您的 shell 中运行以下命令。将 yourdomain 替换为您的实际域名(例如 example.com):
openssl req -new -newkey rsa:2048 -nodes
-keyout yourdomain.key -out yourdomain.csr
-addext "subjectAltName = DNS:yourdomain.com,DNS:www.yourdomain.com"
每个参数的作用如下:
- -new 创建一个新的 CSR。
- -newkey rsa:2048 在生成 CSR 的同时生成一个新的 2048 位 RSA 私钥。如果您的策略要求更大的密钥,可使用 rsa:3072 或 rsa:4096。请不要切换到 ECDSA: Heroku 在手动上传时会拒绝 ECC 密钥。
- -nodes 写出的私钥不带口令保护(在 OpenSSL 3.x 中等效的参数是 -noenc,两者都可用)。Heroku 在执行
heroku certs:add时会拒绝加密的私钥。 - -keyout 和 -out 分别是私钥和 CSR 的输出路径。
- -addext “subjectAltName=DNS:…” 直接嵌入主题备用名称(SAN,需要 OpenSSL 1.1.1 或更高版本)。即使对于单域名证书,现代浏览器和 CA 也都要求包含 SAN 扩展,因此请同时列出主域名(yourdomain.com)以及您计划在 Heroku 上提供服务的任何 www 变体。若是通配符证书,还需列出 *.yourdomain.com。
步骤 3: 填写 CSR 详细信息
OpenSSL 会提示您输入证书的身份信息字段。请按以下方式填写:
- 国家名称(Country Name):您所在组织合法注册国家的两字母 ISO 代码(例如 US)。
- 州或省名称(State or Province Name):州或地区的全称(例如 Nevada)。请不要使用缩写。
- 城市名称(Locality Name):所在城市(例如 Las Vegas)。
- 组织名称(Organization Name):您组织的法定名称。对于域名验证证书,该字段不会被验证,可以留空,但不要直接按回车键: OpenSSL 会填入其配置中定义的默认值,而标准配置默认使用 Internet Widgits Pty Ltd,这最终会出现在您的 CSR 中。请输入一个单独的句点(
.)以使其真正为空。 - 组织单位名称(Organizational Unit Name):已被 CA/浏览器论坛弃用,因此留空即可。
- 通用名称(Common Name):您要保护的完全限定域名(FQDN),例如 www.yourdomain.com。若是通配符证书,请输入 *.yourdomain.com。通用名称也必须出现在 SAN 列表中。
- 电子邮箱地址(Email Address):一个有效的联系邮箱(也可以留空)。
- 挑战密码(A challenge password)和可选公司名称(An optional company name):两者都留空,按回车键跳过即可。
OpenSSL 会在当前目录下写出两个文件:
- yourdomain.csr: 您提交给证书颁发机构的 CSR。
- yourdomain.key: 私钥。请妥善保管此文件并做好备份;在将已签发的证书上传到 Heroku 时您还会再次用到它。
步骤 4: 将 CSR 提交给您的证书颁发机构
用任意文本编辑器打开 yourdomain.csr,复制整个内容块,包括 -----BEGIN CERTIFICATE REQUEST----- 和 -----END CERTIFICATE REQUEST----- 标记。在下单时将其粘贴到 CSR 字段中。
提交之前,您可以使用我们的CSR 解码器本地验证 CSR 内容: 它会显示通用名称、SAN 列表、密钥类型和密钥长度,让您在 CA 发现问题之前先自行检查是否存在错误。
完成 CA 要求的验证步骤(基于 DNS、文件或邮箱)。证书签发后,CA 会发送给您已签名的终端实体证书(通常是 .crt 文件)以及中间 CA 证书包(通常是 .ca-bundle 文件)。接下来请继续下方的上传步骤。
将证书上传到 Heroku
步骤 1: 在应用中注册您的自定义域名
在自定义域名注册到应用之前,Heroku 不会绑定证书。在已登录 Heroku CLI 的终端中运行:
heroku domains:add www.example.com -a your-app-name
将 www.example.com 替换为您的域名,将 your-app-name 替换为您的 Heroku 应用名称。如果还有其他主机名(例如裸根域名或第二个子域名),请重复此命令。该命令会返回一个针对该域名的 DNS 目标,例如 quiet-fire-1234.herokudns.com: 您将在步骤 4 中将 DNS 提供商指向该值。
步骤 2: 构建完整证书链 PEM 文件
Heroku 要求提供单个 PEM 文件,其中终端实体证书在前,中间证书链紧随其后。在 Linux 或 macOS 上,使用 cat 命令拼接文件:
cat yourdomain.crt yourdomain.ca-bundle > server.crt
在 Windows 上,用纯文本编辑器(如 Notepad++ 或 VS Code,不要用 Word)打开这两个文件,将 .ca-bundle 的内容粘贴到 .crt 内容的下方,按此顺序排列,两个内容块之间不要留空行。将合并后的文件保存为 server.crt。如果您的 CA 已经将整个证书链放在了一个 PEM 文件中(叶证书在最上方),您可以直接使用该文件。
步骤 3: 使用 Heroku CLI 上传证书
对于全新安装,使用 certs:add 上传完整证书链 PEM 文件以及匹配的私钥:
heroku certs:add server.crt yourdomain.key -a your-app-name
如果您是在同一个应用上替换现有证书(例如在续期时),请使用 certs:update,这样 Heroku 会保留相同的 DNS 目标:
heroku certs:update server.crt yourdomain.key -a your-app-name
更喜欢使用控制面板?打开应用,进入设置(Settings) > 域名和证书(Domains and certificates),点击配置 SSL(Configure SSL),选择手动(Manually),将合并后的 server.crt 拖入证书插槽,将 .key 文件拖入私钥插槽,然后点击下一步(Next)并确认。
如果上传时出现内部服务器错误(Internal server error),几乎总是因为您机器上的 Heroku CLI 版本过旧。请运行 heroku update 后重试。如果错误仍然存在,请确认证书文件是 PEM 格式的完整证书链(终端实体证书在前,中间证书随后),并确认私钥是与您提交的 CSR 相匹配的 RSA 密钥。
步骤 4: 将 DNS 指向 Heroku DNS 目标
列出您的域名,并复制 Heroku 为每个域名返回的 DNS 目标:
heroku domains -a your-app-name
在您的 DNS 提供商处,为每个域名创建一条记录:
- 子域名(例如 www.example.com): 创建一条指向该 Heroku DNS 目标的 CNAME 记录。
- 顶级/根域名(例如 example.com): 根据 DNS 规范,根域名上不允许使用 CNAME 记录,因此请使用 ALIAS、ANAME 或扁平化 CNAME 记录(具体名称取决于您的 DNS 提供商)指向同一个 Heroku DNS 目标。如果您的 DNS 提供商不支持这些记录类型,请将 DNS 迁移到支持它们的提供商(如 Cloudflare、DNSimple、Route 53、NS1、easyDNS 等)。
请不要将 DNS 指向 your-app-name.herokuapp.com 或任何 *.herokussl.com 主机名: 手动绑定无法通过这两者正确路由。请始终使用 Heroku 分配给该域名的专属 DNS 目标。
验证 CSR 和已部署的证书
在提交 CSR 之前,请先在本地解码以确认通用名称、SAN 列表、密钥类型和密钥长度:
openssl req -in yourdomain.csr -noout -text
或者将 CSR 粘贴到我们的CSR 解码器中,在浏览器中获取相同的信息。
上传后,请确认证书已安装并正在为流量提供服务。在 CLI 中执行:
heroku certs:info -a your-app-name
输出结果会列出证书、签发的 CA、到期日期以及其覆盖的域名。然后在浏览器中通过 https:// 打开您的网站,检查是否显示锁形图标,并使用我们的SSL Checker进行更深入的外部扫描,以确认证书链是否完整,协议配置是否正确。


