在 Ubuntu 上获取 TLS 证书:Certbot 自动签发与内部 CA

原文由 Canonical / Ubuntu Server documentation contributors 编写:Obtain TLS certificates。本文为中文整理译文,依据 2026-10-05 读取版本,原页面显示最后更新于 2026-06-26;这不是首次发表日期。

TLS 证书用来验证服务器身份,并配合私钥建立加密连接。面向互联网的服务通常选择公开受信任的证书颁发机构,例如 Let’s Encrypt;内部网络或隔离环境也可以由自己管理 CA,为服务签发证书,但必须把 CA 证书加入每个客户端的信任链。

TLS 证书两条路径:公网域名经 ACME HTTP-01 或 DNS-01 验证后由 Let’s Encrypt 签发并自动续期;内部 CA 用根私钥签发服务证书,并向客户端分发根证书建立信任。
公开 CA 与内部 CA 的验证和信任关系。未完纪原创技术示意,非操作截图。

用 Let’s Encrypt 获取证书

Let’s Encrypt 由 Internet Security Research Group(ISRG)运营,通过 ACME 协议自动签发证书。原文描述的是 90 天有效期及自动续期机制;证书生命周期政策会变化,应以实际签发结果和当前 CA 文档为准,不能在运维系统里把原文天数写死。

原文 HTTP-01 流程要求先有域名,并让 DNS 记录指向服务器。签发和续期时,CA 必须能够从互联网访问该域名的 TCP 80 端口,防火墙、负载均衡和应用路由都需要放行对应的验证请求。

Ubuntu 文档推荐使用 Certbot 作为 ACME 客户端,通过 snap 安装:

sudo snap install --classic certbot

这条命令会安装具有 classic 权限的系统软件,后面的 Certbot 命令也会以管理员权限读写证书和服务配置。以下域名均为示例,需要替换成自己控制的域名。本次没有在任何服务器上执行这些操作。

选择与现有服务匹配的模式

已经运行 nginx 时,插件会寻找与域名匹配的 server block,通常位于 /etc/nginx/sites-enabled/,原地添加 TLS 指令并重新加载服务:

sudo certbot --nginx -d example.com -d www.example.com

Apache 插件会类似地寻找匹配的 VirtualHost,通常位于 /etc/apache2/sites-enabled/,修改配置并 reload:

sudo certbot --apache -d example.com -d www.example.com

这两种模式不仅申请证书,也会修改 Web 服务配置。实际操作前应保存配置副本,并确认使用的域名、虚拟主机和服务重载方式。

没有 Web 服务器时,可以使用 standalone 模式。Certbot 会临时监听 80 端口完成验证,因此同一端口不能已经被其他服务占用:

sudo certbot certonly --standalone -d example.com -d www.example.com

如需停掉现有服务,必须考虑停机窗口和续期时同样的端口条件。不要为了申请证书盲目停止生产服务。

已经有 Web 服务器,又希望自行管理 TLS 配置时,可以选择 webroot 模式。把 -w 指向该站点实际提供的文档根目录:

sudo certbot certonly --webroot -w /var/www/html -d example.com

这里的目录必须确实通过目标域名可访问;路由、重定向或认证规则不能挡住 ACME 验证文件。certonly 只负责获取证书,不替你完成服务接入。

每个 -d 增加一个 Subject Alternative Name(SAN)。需要扩展已有证书覆盖的域名时,应一次列出希望保留的旧域名与新增域名,并核对 Certbot 选择的证书:

sudo certbot --nginx -d example.com -d www.example.com -d mail.example.com

80 端口不可达,或需要通配符证书

上述示例采用 HTTP-01。无法开放 80 端口,或需要 *.example.com 通配符证书时,可以使用 DNS-01:在 DNS 中发布指定 TXT 记录供 CA 验证,不要求证书服务器开放入站端口。Certbot 为常见 DNS 服务商提供插件。

DNS 自动化所用凭据应限制到必要区域和记录操作,并避免写进公开配置或日志。内网服务器可以借助 DNS 验证域名控制权,但完全隔离的环境仍需要能与外部 CA 通信的受控代理或集中签发节点;“无入站端口要求”不等于“不需要任何外部连接”。

原文还提到 ACME 代理(如 step-ca)与集中运行的 acme.sh、lego。大规模主机可以集中签发、分发证书;需要自建信任体系时,也可以用内部 CA。代理或集中管理不会自动免除域名验证与客户端信任要求。

找到证书文件并接入服务

成功签发后,Certbot 通常把活动文件放在 /etc/letsencrypt/live/<domain>/:

文件 内容
fullchain.pem 服务器证书和中间证书,多数服务应使用这一完整链。
privkey.pem 服务器私钥,必须限制读取权限。
cert.pem 仅服务器证书。
chain.pem 仅中间证书。

nginx 中可以这样引用:

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

不要为了让服务“读得到”就把私钥设为所有用户可读,也不要把 privkey.pem 放进 Web 根目录、代码仓库或共享备份。

自动续期与服务重载

原文 snap 安装方式会配置 systemd 定时器,每天尝试续期两次。可以查看定时器:

sudo systemctl status snap.certbot.renew.timer

原文还给出续期演练命令:

sudo certbot renew --dry-run

编辑校注:--dry-run 不会把正式证书替换成新签发的正式证书,但它仍会联系测试 ACME 服务、进行域名验证,并可能触发配置中的相关钩子或临时配置处理。不要把它理解为绝对无网络、无服务影响的纯只读检查。本次没有执行该命令。

通过 nginx 或 Apache 插件配置的服务,会在成功续期后由插件处理 reload。其他服务可能需要 deploy hook。原文要求创建 /etc/letsencrypt/renewal-hooks/deploy/reload-service.sh,其中的服务名需换成实际服务:

#!/bin/sh
systemctl reload <your-service>
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-service.sh

<your-service> 是说明用的占位参数,不能原样执行。应先确认服务支持 reload,并保证脚本及其父目录只能由可信管理员修改;这个钩子会在证书流程中以高权限运行。

为内部网络建立手动 CA

当多个内部服务都需要证书时,由一个内部 CA 统一签名通常比管理许多互不相关的自签名服务证书更方便。客户端仍必须信任这个 CA,Ubuntu 上的系统信任安装方法见安装根 CA 证书。只复制到一个目录并不保证所有程序自动信任它。

以下保留原文手动流程,同时标出需要修订之处。它适合理解 CA 数据库、CSR 和签名的关系,不是包含吊销、审计、离线根 CA、密钥恢复等机制的完整生产 PKI 方案。

创建目录和数据库

sudo mkdir /etc/ssl/CA
sudo mkdir /etc/ssl/newcerts
sudo sh -c "echo '01' > /etc/ssl/CA/serial"
sudo touch /etc/ssl/CA/index.txt

serial 记录下一次签发所用序列号,index.txt 是已签发证书的数据库。这些是新 CA 的初始化步骤,不能在已有 CA 上重复初始化或覆盖序列号与数据库。否则可能破坏签发记录或重用序列号。部署前先确认这些路径没有其他 CA 数据。

原文编辑系统 /etc/ssl/openssl.cnf 的 [ CA_default ]:

dir             = /etc/ssl
database        = $dir/CA/index.txt
certificate     = $dir/certs/cacert.pem
serial          = $dir/CA/serial
private_key     = $dir/private/cakey.pem

编辑建议:系统级 OpenSSL 配置可能被其他工具共享,更稳妥的做法是复制为该 CA 的专用配置,并始终通过 -config 显式指定。本文保留原路径便于对照;应用时应检查权限、现有配置和回退方案。

生成根证书

openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 3650
sudo mv cakey.pem /etc/ssl/private/
sudo mv cacert.pem /etc/ssl/certs/

命令会询问根私钥口令和证书主题信息。-extensions v3_ca 依赖当前 OpenSSL 配置中相应扩展节;-days 3650 是原文选择的有效期,不是必须遵守的策略。根私钥应加密、严格控制访问,移动文件前要确认不会覆盖已有 CA。CA 私钥一旦泄漏,攻击者就能伪造该信任体系内的证书。

生成服务器密钥与 CSR

原文使用以下历史命令生成加密 RSA 私钥:

openssl genrsa -des3 -out server.key 2048

随后输入并确认口令。原文的“至少八个字符”及 -des3 是旧式建议,不能作为今天的完整密钥保护标准。实际项目应使用当前 OpenSSL 支持的密钥算法与现代加密方式,并采用足够强的口令。

为了让服务能无人值守启动,原文接着移除服务器私钥的口令。这会降低密钥落盘后的保护能力,必须依靠文件权限、进程隔离和宿主机安全控制。CA 私钥不应因此一起取消口令。

原文错误与修订:网页将“导出无口令密钥”和两条 mv 命令错误连成了带 > mv 的一行。> 是 shell 重定向,不是执行下一条命令的分隔符;照抄可能截断文件或失败。下面按原意拆成独立命令,并新增 umask 077:

umask 077
openssl rsa -in server.key -out server.key.insecure
mv server.key server.key.secure
mv server.key.insecure server.key

这段修订只解释原流程。必须在没有同名重要文件的受控目录中运行,并保护 server.key.secure;明文私钥不应进入共享位置。随后用无口令的 server.key 创建 CSR:

openssl req -new -key server.key -out server.csr

程序会要求填写证书主题信息。原文这里再次说会询问私钥口令,但若上一步确实已移除口令,就不会再询问这把私钥的口令。这一点在译文中作了更正。

签名时别漏掉服务域名扩展

原文用以下命令由 CA 签发:

sudo openssl ca -in server.csr -config /etc/ssl/openssl.cnf

输入 CA 私钥口令后,还需要确认签名和写入数据库。首张证书在原文示例中写到 /etc/ssl/newcerts/01.pem,后续按序列号增加。将其中从 -----BEGIN CERTIFICATE----- 到 -----END CERTIFICATE----- 的 PEM 部分保存为描述性名称,例如 mail.example.com.crt。

编辑补充:原文没有明确给服务器证书配置 SAN,不能据此保证现代客户端能通过域名校验。需要在签发证书中核实正确的 DNS 名和服务器用途扩展。以下是与原文不同的显式扩展示例,域名必须按实际服务替换,并由 CA 管理员核实 CSR 申请者的控制权:

[ server_cert ]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:mail.example.com

若将该内容保存为 server-ext.cnf,签发时显式指定扩展文件:

sudo openssl ca -in server.csr -config /etc/ssl/openssl.cnf -extfile server-ext.cnf -extensions server_cert

该扩展示例针对前面的 RSA 服务器证书,是静态修订示例;没有测试特定 OpenSSL 版本或服务的兼容性。不要不经验证就把 CSR 中任意扩展复制成 CA 签发权限,尤其要避免把最终实体错误签成 CA。

安装证书并分发信任

把服务器证书和私钥复制到需要它们的主机,再配置应用使用相应文件。原文使用:

sudo cp server.key /etc/ssl/private/
sudo cp mail.example.com.crt /etc/ssl/certs/

证书可以公开分发,私钥不可以。应核对目标文件的属主和权限,只给实际服务需要的读取权限;简单复制命令并没有完成权限审核。

对于可以显式指定 CA 文件的应用,可向其提供 cacert.pem。需要系统范围信任时,则按 Ubuntu 的根证书安装流程配置并更新信任库;不能把 cakey.pem 分发给客户端。部署后还要检查证书链、SAN、有效期、服务读权限和真实客户端握手。

来源与审核边界

进一步阅读:Let’s Encrypt 文档、Certbot 文档、Ubuntu 证书概念说明。原文也链接了 TLS 的背景资料。

本次完成全文对照及静态命令审核,没有安装 snap、生成私钥、申请证书、修改服务器配置或执行续期演练。审核发现并标注了错误重定向、序列号覆盖、无口令私钥、缺少 SAN 和高权限钩子等实际风险;没有发现其他问题不等于不存在漏洞。所有输出描述来自原文,未伪造运行记录。

归属:Canonical / Ubuntu Server documentation contributors,原页面版权标注 © 2026。未从该页面确认额外独立许可证,不推定其许可条款。编辑校注和自绘图由未完纪提供。

原文密钥生成的历史提示

以下是源文展示的提示,不是本次运行。原文还提到-des3的四字符最低长度与至少八字符建议;这些旧阈值不作为当前安全标准。

Generating RSA private key, 2048 bit long modulus
..........................++++++
.......++++++
e is 65537 (0x10001)
Enter pass phrase for server.key:
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容