Certbot 和 Let’s Encrypt 的关系

Let’s Encrypt

  • 一个免费、自动化、开放的公共证书颁发机构(CA)。
  • 通过 ACME(Automatic Certificate Management Environment)协议向域名所有者颁发 DV(Domain Validation)TLS/SSL 证书。

Certbot

  • 由 Electronic Frontier Foundation (EFF) 维护的开源 ACME 客户端。
  • 主要目标是简化与 Let’s Encrypt 之间的交互:
    • 自动化域名验证(HTTP-01、DNS-01、TLS-ALPN-01 等)
    • 安装并续期证书
    • 更新 Web 服务器配置(Apache、Nginx、Lighttpd 等)
  • Certbot 也能与任何兼容 ACME 的 CA 通信,不限于 Let’s Encrypt。

典型工作流程

  1. 解析参数并检测服务器类型。
  2. 选择并执行挑战(例如在 /.well-known/acme-challenge/ 下写入 token)。
  3. Let’s Encrypt 回访验证域名归属。
  4. 验证通过后签发证书;Certbot 下载并安装到本地。
  5. 创建定时任务 certbot renew 自动续期。

开始实验

实验环境:Amazon Linux 2023 (AL2023)

知识补充

  • dnf(Dandified YUM) 是 RPM-系 Linux 发行版的下一代包管理器。它在功能上取代了传统的 yum,两者命令参数几乎保持兼容。
  • RPM 一开始叫 Red Hat Package Manager,后来改名为递归含义的 RPM Package Manager。
  • RPM-系发行版 是把 RPM 作为原生软件包格式与核心包管理工具链的那一族 Linux 发行版。常听到的 Fedora / RHEL / CentOS / AlmaLinux / Rocky Linux / openSUSE / SUSE Linux Enterprise / Amazon Linux 2023 等。
  • dnf 不是对 rpm CLI 的简单封装,而是调用 librpm 完成最终操作。
包管理器代表发行版归属
dnf / yumFedora, RHEL, CentOSRPM
zypperopenSUSE, SLERPM
apt / apt-getDebian, UbuntuDEB
pacmanArch Linuxtar.xz
apkAlpine.apk
  • snap 是一种由 Canonical(Ubuntu 的开发公司)推出的跨发行版应用打包和分发格式,也指围绕它的一整套生态系统。
    • 跨发行版。同一个 snap 包可以在几十种发行版上直接安装运行,不依赖各自的 RPM/Deb 系统仓库。
    • 自包含(bundled)依赖。snap 包内部包含所有依赖,无需外部安装。
    • https://snapcraft.io/

Launch an AWS EC2 instance

  • Instance type: t2.nano
  • Username: ec2-user
  • Security Groups: Allow HTTP and HTTPS
  • Public IPv4: 35.86.90.4

配置 nginx

sudo dnf update -y

sudo dnf install -y nginx
nginx -v
# nginx version: nginx/1.28.0

sudo systemctl start nginx
sudo systemctl enable nginx
systemctl status nginx
# Started nginx.service - The nginx HTTP and reverse proxy server.

直接通过 http://35.86.90.4,会看到默认的 nginx 欢迎页面。

sudo vi /etc/nginx/conf.d/default.conf
#
server {
    listen       80;
    listen       [::]:80;
    server_name  tmp.yifans.net;
    root         /usr/share/nginx/html;

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}
sudo nginx -t
sudo systemctl reload nginx

将自己的域名(tmp.yifans.net)解析到 35.86.90.4,然后访问 http://tmp.yifans.net 同样看到 nginx 欢迎页面,游览器显示 Not Secure。

配置 certbot

# 暂无官方支持 AL2023
sudo wget -O /etc/yum.repos.d/snapd.repo \
    https://bboozzoo.github.io/snapd-amazon-linux/al2023/snapd.repo
sudo dnf install -y snapd
sudo systemctl enable --now snapd.socket

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

certbot --version
# certbot 4.1.1
# 前置 nginx 配置中要有 server_name tmp.yifans.net;
sudo certbot --nginx -d tmp.yifans.net
# 全自动完成

访问 http://tmp.yifans.net 会自动跳转 https。

# 看看被 certbot 自动修改的 nginx 配置
cat /etc/nginx/conf.d/default.conf
server {
    server_name  tmp.yifans.net;
    root         /usr/share/nginx/html;

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/tmp.yifans.net/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/tmp.yifans.net/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = tmp.yifans.net) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen       80;
    listen       [::]:80;
    server_name  tmp.yifans.net;
    return 404; # managed by Certbot
}
# 看看 certbot 预置的参数
# include /etc/letsencrypt/options-ssl-nginx.conf;
cat /etc/letsencrypt/options-ssl-nginx.conf
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file. Contents are based on https://ssl-config.mozilla.org

ssl_session_cache shared:le_nginx_SSL:10m;
# 在内存里创建名为 le_nginx_SSL 的共享会话缓存区域,大小 10 MiB。
# 能加速后续同客户端的 TLS 握手(避免完整密钥交换)。
# 10 MiB 足够保存约 40 000 个会话条目。

ssl_session_timeout 1440m;
# 单位是分钟(1440 m = 24 h)。
# 表示缓存的会话条目过期时间;设为一天可在常见浏览器会话周期内复用。

ssl_session_tickets off;
# 关闭 TLS Session Tickets。
# 原因:早期实现无法便捷轮换 ticket 加密密钥,导致前向安全受损。

ssl_protocols TLSv1.2 TLSv1.3;
# 明确只允许 1.2 / 1.3。
# 关闭已不安全的 SSLv3、TLS 1.0、TLS 1.1。

ssl_prefer_server_ciphers off;
# 让客户端来决定从交集里选哪一组加密套件(服务器不强制优先级)。
# 在只开放现代安全套件的前提下,这样做兼容性好且简化维护。
# 如果你想严格控制,可改为 on 并自行调整 ssl_ciphers 顺序。

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
# 仅保留 GCM / ChaCha20-Poly1305 这一代 AEAD 套件;弃用 CBC、RC4、3DES 等。
# ECDHE-ECDSA(椭圆曲线 DH,证书是 ECDSA)
# ECDHE-RSA(证书是 RSA)
# DHE-RSA(传统 DH,给极旧设备兜底)
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

`ssl_dhparam` 告诉 Nginx 在使用 DHE(Diffie-Hellman Ephemeral)握手方式时,不用默认的 1024 位弱参数,而改用一份 自定义、更安全的 DH 参数文件。

DHE 是 TLS/SSL 协议中的一种「密钥交换算法」。它的核心作用只有两点:
  - 让客户端与服务器在 公网信道 上安全地“协商出”一个对称加密用的随机密钥。
  - 提供 前向安全(Forward Secrecy):哪怕以后服务器的长期私钥被泄露,过去抓到的加密数据也无法解密。
# 看看证书
sudo openssl x509 -in /etc/letsencrypt/live/tmp.yifans.net/fullchain.pem -noout -text | grep yifans.net

        Subject: CN=tmp.yifans.net
                DNS:tmp.yifans.net

只获取证书

首先需要将 tmp-certonly.yifans.net 解析到 35.86.90.4,为了自动完成 acme challenge。

sudo vi /etc/nginx/conf.d/certonly.conf
server {
    listen       80;
    listen       [::]:80;
    server_name  tmp-certonly.yifans.net;
    root         /usr/share/nginx/html;

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }
}
sudo nginx -t
sudo systemctl reload nginx

sudo certbot certonly --nginx

We recommend selecting either all domains, or all domains in a VirtualHost/server block.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: tmp.yifans.net
2: tmp-certonly.yifans.net

# 选择 2
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/tmp-certonly.yifans.net/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/tmp-certonly.yifans.net/privkey.pem
This certificate expires on 2025-10-01.
# /etc/nginx/conf.d/certonly.conf 没有被自动修改,需要手动添加证书

Wildcard Certificate

  • 需要 DNS Credentials。
  • *.example.com 不覆盖 example.com, hello.goodbye.example.com
  • *.goodbye.example.com 可覆盖 hello.goodbye.example.com
  • 不可以申请 *.*.example.com 只能一个 * asterisk。

可以通过 DNS Plugins 插件申请 Wildcard Certificate,但是我觉得 manual 更简单。

sudo certbot certonly --manual -d '*.tmp.yifans.net' --preferred-challenges dns

Please deploy a DNS TXT record under the name:

_acme-challenge.tmp.yifans.net.

with the following value:
...

# 访问 https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.tmp.yifans.net. 预测试配置结果。
# 如果看到对应的值,按 Enter 继续。

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/tmp.yifans.net-0001/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/tmp.yifans.net-0001/privkey.pem
# 看看证书
sudo openssl x509 -in /etc/letsencrypt/live/tmp.yifans.net-0001/fullchain.pem -noout -text | grep yifans.net

        Subject: CN=*.tmp.yifans.net
                DNS:*.tmp.yifans.net
sudo vi /etc/nginx/conf.d/wildcard.conf
server {
    server_name  *.tmp.yifans.net;
    root         /usr/share/nginx/html;

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    }

    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/tmp.yifans.net-0001/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tmp.yifans.net-0001/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

server {
    listen 80;
    server_name *.tmp.yifans.net;
    return 301 https://$host$request_uri;
}
sudo nginx -t
sudo systemctl reload nginx

1.tmp.yifans.net 解析到 35.86.90.4,然后访问 https://1.tmp.yifans.net,在 Chrome 的证书信息里可以看到 Common Name (CN) *.tmp.yifans.net

证书续期

sudo certbot renew --dry-run

References

– EOF –