Certbot 是一个开源的命令行工具,用于自动化获取和续期 Let's Encrypt 颁发的 SSL/TLS 证书。Let's Encrypt 是一个免费的、自动化的、开放的证书颁发机构(CA),它提供免费的 SSL/TLS 证书,用于加密网站流量。

每天运行一次 Certbot 就能实现自动续期30天内过期的证书。

基本概念

通配符证书

通配符证书(wildcard certificate)是可以与多个子域名一起使用的公钥证书。与传统证书相比,通配符证书可以比每个子域的证书更便宜、更方便。

证书是针对域名颁发的,与具体的主机无关,已经申请的证书可以迁移到任何主机。因此颁发证书只需验证你对域名的所有权。

ACME

自动证书管理环境(Automatic Certificate Management Environment, ACME)是一种通信协议,用于自动化证书颁发机构与其用户的 Web 服务器之间的交互,允许以非常低的成本自动部署公钥基础设施。

ACME使用“客户端/服务器”架构,使用HTTPS传输数据。想要通过ACME协议申请证书,证书颁发机构必须支持ACME,实现ACME服务器,而我们需要一个ACME客户端。

ACME客户端
https://letsencrypt.org/zh-cn/docs/client-options/

Let's Encrypt

Let's Encrypt是由Internet Security Research Group(ISRG)运营的非营利性证书颁发机构,它免费为传输层安全(TLS)加密提供X.509证书。它是世界上最大的证书颁发机构,被超过 2.65 亿个网站使用,目标是所有网站都使用HTTPS。

Let's Encrypt支持ACME协议,并支持通配符证书。

Certbot

Certbot is EFF's tool to obtain certs from Let's Encrypt and (optionally) auto-enable HTTPS on your server.
It can also act as a client for any other CA that uses the ACME protocol.
https://github.com/certbot/certbot

Certbot是一个ACME客户端,也是ACME客户端的参考实现,使用Python编写。Certbot默认使用Let's Encrypt作为证书颁发机构。

验证方式

上文说到,证书颁发机构需要验证你对域名的所有权,然后才能给你证书。
虽然ACME客户端可能有五花八门的验证选项,但是归结起来只有两种类型:HTTP质询DNS质询

HTTP质询

这是当今最常见的验证方式。与ACME服务器沟通后,ACME客户端将一个特定的文件放在主机Web服务器的一个特定路径上。ACME服务器会通过申请的域名与此路径访问这个文件,如果一切正确,则验证完毕。HTTP质询只能使用80端口

可以看出,HTTP质询需要你事先添加DNS记录,使你申请证书的域名指向运行ACME客户端的主机,并且该主机必须是可公网访问的。其次,需要一个已经在运行的Web服务器,ACME客户端需要足够的权限在Web服务器下放置文件。

HTTP质询不支持通配符证书。

DNS质询

DNS质询与Web服务器无关,而是通过检查DNS记录来验证对域名的所有权。ACME服务器只需要检查域名下特定的TXT记录即可完成验证。

为了让ACME客户端自动添加TXT记录,DNS托管商必须提供编辑DNS记录的API,并且由DNS托管商提供身份认证的方案。此外,ACME客户端还要有支持这些API的插件。

DNS质询看起来麻烦,但更具普适性,而且功能强大。DNS质询不依赖于具体主机,并且支持通配符证书

Certbot 的基本使用

docker pull certbot/certbot
docker run -it --rm certbot/certbot -h

验证方式

  • 通过 HTTP 请求验证,会向http://你的域名/.well-known/acme-challenge/发送一条请求。
  • 通过 DNS 解析,需要在域名解析中增加一条_acme-challenge.你的域名的TXT记录用于验证。

命令

certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...

Certbot can obtain and install HTTPS/TLS/SSL certificates.  By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:

obtain, install, and renew certificates:
    (default) run   Obtain & install a certificate in your current webserver
    certonly        Obtain or renew a certificate, but do not install it
    renew           Renew all previously obtained certificates that are near
expiry
    enhance         Add security enhancements to your existing configuration
   -d DOMAINS       Comma-separated list of domains to obtain a certificate for

  (the certbot apache plugin is not installed)
  --standalone      Run a standalone webserver for authentication
  (the certbot nginx plugin is not installed)
  --webroot         Place files in a server's webroot folder for authentication
  --manual          Obtain certificates interactively, or using shell script
hooks

   -n               Run non-interactively
  --test-cert       Obtain a test certificate from a staging server
  --dry-run         Test "renew" or "certonly" without saving any certificates
to disk

manage certificates:
    certificates    Display information about certificates you have from Certbot
    revoke          Revoke a certificate (supply --cert-name or --cert-path)
    delete          Delete a certificate (supply --cert-name)
    reconfigure     Update a certificate's configuration (supply --cert-name)

manage your account:
    register        Create an ACME account
    unregister      Deactivate an ACME account
    update_account  Update an ACME account
    show_account    Display account details
  --agree-tos       Agree to the ACME server's Subscriber Agreement
   -m EMAIL         Email address for important account notifications

More detailed help:

  -h, --help [TOPIC]    print this message, or detailed help on a topic;
                        the available TOPICS are:

   all, automation, commands, paths, security, testing, or any of the
   subcommands or plugins (certonly, renew, install, register, nginx,
   apache, standalone, webroot, etc.)
  -h all                print a detailed help page including all topics
  --version             print the version number
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_注意_:==修改其中的任何文件 /etc/letsencrypt 可能会损坏它们==,因此 Certbot 无法再正确管理其证书,我们不建议这样做..

certbot的命令有很多种不同的参数,这些参数也主要是为了自动生成http验证文件或自动添加dns解析等功能,主要的大体说下:

--manual

sudo certbot certonly --manual \
    --preferred-challenges=http \
    -d example.com \
    -d www.example.com
  • certonly: 只获取证书,不自动配置 Web 服务器。
  • --manual: 启用手动模式。
  • --preferred-challenges=http: 使用 HTTP 验证方式(默认是 DNS 验证)。
  • 选择使用 DNS 验证(--preferred-challenges=dns),你需要手动在 DNS 记录中添加 TXT 记录。
  • -d example.com -d www.example.com: 指定你要获取证书的域名。

运行完成后需要在 http://example.com/.well-known/acme-challenge/ 路径下创建一个文件,文件内容为 Certbot 提供的字符串。

创建文件后,Certbot 会自动尝试访问该 URL 进行验证。如果验证成功,Certbot 会生成 SSL 证书,并将其存储在 /etc/letsencrypt/live/example.com/ 目录下

然后再配置 Nginx

server {
    listen 443 ssl;
    server_name example.com www.example.com;

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

    # 其他配置...
}

自动续期

certbot renew

--nginx 和 --apache

apt-get install certbot python3-certbot-nginx

运行之前你需要创建一个基本的 Nginx 配置

server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 404; 
}

获取并自动配置 Nginx

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

Apache

apt-get install certbot python3-certbot-apache
certbot --apache -d example.com -d www.example.com

--dns-xxx

apt-get install certbot python3-certbot-dns-cloudflare
apt-get install certbot python3-certbot-dns-google
apt-get install certbot python3-certbot-dns-route53

创建令牌

# cloudflare.ini
dns_cloudflare_api_token = your-cloudflare-api-token
chmod 600 cloudflare.ini

Cloudflare

certbot certonly --dns-cloudflare \
    --dns-cloudflare-credentials /path/to/cloudflare.ini \
    -d example.com 
    -d www.example.com

其他服务商类似

--standalone

再80端口创建一个Web服务用于验证。

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

--webroot

 --webroot 是一种使用 Certbot 获取 SSL 证书的方式,它通过在现有的 Web 服务器(如 Nginx 或 Apache)的 Web 根目录下创建一个临时文件来验证域名所有权。这种方式不需要停止现有的 Web
 服务器,也不会占用 80 或 443 端口。

certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com
  • certonly: 只获取证书,不自动配置 Web 服务器。
  • --webroot: 使用 Webroot 模式,Certbot 会在指定的 Web 根目录下创建临时文件。
  • -w /var/www/html: 指定 Web 根目录的路径。
  • -d example.com -d www.example.com: 指定你要获取证书的域名。
     
    通过webroot的方式运行后,会在两个地方产生文件:
  • 一个是在命令行配置的--webroot-path指定目录下产生临时文件,用于http验证。
  • 一个是验证成功会产生存放证书的文件,默认是在/etc/letsencrypt/live/你的域名目录下,需要注意的是这些证书是个软链接,对应着../archive下,所以我们在做volume映射时不要只映射到live这个目录,而是要映射/etc/letsencrypt这个目录,否则无法找到相关的证书文件。

限制

Certbot申请证书是有次数限制的,重复申请5次以上,再次请求会报too many certificates already issued...等错误,会停用一周后才能再继续,此时只能再换个域名或者是等一周了,参考速率限制
Certbot 不会自动添加到定时任务 cron, 所以需要定时运行。

简单使用

certbot certonly --webroot --webroot-path path/to/webroot --domain subdomain.example.com
# 自动配置 web 服务
certbot --nginx --domain subdomain.example.com
certbot --apache --domain subdomain.example.com
# 续期
certbot renew
# --dry-run 模拟结果
certbot --webroot --webroot-path path/to/webroot --domain subdomain.example.com --dry-run
# 获取测试证书
certbot --webroot --webroot-path path/to/webroot --domain subdomain.example.com --test-cert

Docker

使用主机自带的 Corn 定时重启 Certbot

Compose

services:
  nginx:
    image: nginx:1.15-alpine
    restart: unless-stopped
    container_name: nginx
    volumes:
      - ./data/nginx:/etc/nginx/conf.d
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
  certbot:
    image: certbot/certbot
    container_name: ssl
    volumes:
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
# 启动
docker compose up nginx -d
docker compose exec -it ssl -d example.com

使用主机自带的corn运行容器

# 每天2点运行 证书更新 和 重启 Nginx
0 2 * * * docker exec -it ssl renew --quiet
30 2 * * * docker exec -it nginx nginx -s reload

Compose 配置复杂度蛮高的。

构建容器

在 Nginx 中按照 Certbot 并配置定时任务

FROM nginx:stable-alpine

RUN apk add --no-cache certbot certbot-nginx && \
    echo "0 2 * * * /usr/bin/certbot renew --quiet" | tee -a /etc/crontabs/root && \
    echo "30 2 * * *  /usr/sbin/nginx -s reload" | tee -a /etc/crontabs/root

EXPOSE 80
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]

OR

FROM nginx:stable-alpine

RUN apk add --no-cache certbot certbot-nginx

COPY crontab /var/spool/cron/crontabs/root

EXPOSE 80
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]

Crontab 定时执行

# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min
0       *       *       *       *       run-parts /etc/periodic/hourly
0       2       *       *       *       run-parts /etc/periodic/daily
0       3       *       *       6       run-parts /etc/periodic/weekly
0       5       1       *       *       run-parts /etc/periodic/monthly
# 当天晚上2点执行一次
0       2       *       *       *       /usr/bin/certbot renew  >> /var/log/renew.log 2>&1 && /usr/sbin/nginx -s reload >> /var/log/reload.log 2>&1

或者

(crontab -l 2>/dev/null; echo "0 2 * * * /usr/bin/certbot renew --quiet") | crontab -

(crontab -l 2>/dev/null; echo "0 3 * * *  /usr/sbin/nginx -s reload") | crontab -

资料参考

Letsencrypt 官网
https://letsencrypt.org/zh-cn/

使用Certbot与Cloudflare插件申请通配符证书
https://juejin.cn/post/7069995574266691614

Certbot使用DNS和文件验证两种方式申请SSL证书
https://blog.ansheng.me/post/certbot-uses-dns-and-file-verification-to-apply-for-ssl-certificates.html

Letsencrypt通过DNS的TXT记录来验证域名有效性
https://opstrip.com/2018/12/28/Getting-Letsencrypt-Certificate-with-DNS-TXT/

Docker环境下自动更新Let’s Encrypt SSL证书
https://www.cnblogs.com/gao88/p/10596143.html

docker-nginx/stable/alpine/Dockerfile
https://github.com/nginxinc/docker-nginx/blob/master/stable/alpine/Dockerfile

项目参考

Boilerplate for nginx with Let’s Encrypt on docker-compose
https://github.com/wmnnd/nginx-certbot

Automatically create and renew website certificates for free using the Let's Encrypt certificate authority.
https://github.com/JonasAlfredsson/docker-nginx-certbot

开源的SSL证书管理工具,可以帮助你自动申请、部署SSL证书,并在证书即将过期时自动续期。
https://github.com/usual2970/certimate

标签: Nginx, SSL

添加新评论