参考文献

certbot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# certbot --help

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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
--nginx Use the Nginx plugin for authentication & installation
--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-path)
delete Delete a certificate

manage your account with Let's Encrypt:
register Create a Let's Encrypt ACME account
--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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

申请证书

1
2
3
certbot certonly -d 要申请的域名
# 示例
certbot certonly -d xxx.com

查看申请的证书信息

1
2
3
4
5
6
7
8
9
10
11
# certbot certificates

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
Certificate Name: med-3d.com
Domains: xxxx.com
Expiry Date: 2023-12-24 06:13:43+00:00 (VALID: 88 days)
Certificate Path: /etc/letsencrypt/live/xxxx.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/xxxx.com/privkey.pem

手动续期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxxx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The following certs are not due for renewal yet:
/etc/letsencrypt/live/xxxx.com/fullchain.pem expires on 2023-12-24 (skipped)
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

certbot 插件

Plugin Auth Inst Notes Challenge Types(及端口)
apache 自动获取并安装证书 tls-sni-01 (443)
webroot 已有运行的服务,通过验证 webroot 目录获取证书 http-01 (80)
nginx 使用 nginx 自动获取和安装证书 tls-sni-01 (443)
standalone 建立一个独立的 Web 服务,需要可用的 80 或 443 端口,适用于没有类似 nginx 和 apache 的服务环境 http-01 (80) 或 tls-sni-01 (443)
DNS plugins 通过修改 DNS 服务器的 TXT记录来获取证书,支持通配符证书,仅可通过此方式获取 dns-01 (53)
manual 通过手动操作来获取证书,支持添加定制脚本完成任务 http-01 (80), dns-01 (53), 或 tls-sni-01 (443)
  • 使用standalone插件,那么需要使用80443端口,因为要建一个监听这些端口的服务,注意端口占用问题
  • 使用webroot方式,如果你使用了nginx,那么你需要更改一些nginx配置,确保能验证你对该域名的所有权限

webroot

1
2
3
certbot certonly --webroot 
-w /var/www/example -d www.example.com -d example.com
-w /var/www/other -d other.example.net -d another.other.example.net
  • certonly: 只获取证书,不安装

  • --webroot : 定义使用的插件方法是webroot

  • --webroot-path: 简写为-w 表示目录位置

  • 通过webroot的方式运行后,会在两个地方产生文件:

    • 一个是在命令行配置的--webroot-path指定目录下产生临时文件,用于http验证。

    • 一个是验证成功会产生存放证书的文件,默认是在/etc/letsencrypt/live/你的域名目录下,需要注意的是这些证书是个软链接,对应着../archive下,所以我们在做volume映射时不要只映射到live这个目录,而是要映射/etc/letsencrypt这个目录,否则无法找到相关的证书文件。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      # ll /etc/letsencrypt/
      total 56
      drwxr-xr-x 9 root root 4096 Sep 26 14:43 ./
      drwxr-xr-x 97 root root 4096 Sep 25 15:02 ../
      drwx------ 4 root root 4096 Sep 26 11:29 accounts/
      drwx------ 3 root root 4096 Sep 25 15:13 archive/
      -rw-r--r-- 1 root root 121 Feb 11 2019 cli.ini
      drwxr-xr-x 2 root root 4096 Sep 26 13:25 csr/
      drwx------ 2 root root 4096 Sep 26 13:25 keys/
      drwx------ 3 root root 4096 Sep 25 15:13 live/
      -rw-r--r-- 1 root root 1143 Sep 25 15:02 options-ssl-nginx.conf
      drwxr-xr-x 2 root root 4096 Sep 25 15:13 renewal/
      drwxr-xr-x 5 root root 4096 Sep 7 14:02 renewal-hooks/
      -rw-r--r-- 1 root root 424 Sep 25 15:02 ssl-dhparams.pem
      -rw-r--r-- 1 root root 64 Sep 25 15:02 .updated-options-ssl-nginx-conf-digest.txt
      -rw-r--r-- 1 root root 64 Sep 25 15:02 .updated-ssl-dhparams-pem-digest.txt

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # ll /etc/letsencrypt/live/xxx.com/
      total 16
      drwxr-xr-x 3 root root 4096 Sep 26 13:07 ./
      drwx------ 3 root root 4096 Sep 25 15:13 ../
      lrwxrwxrwx 1 root root 34 Sep 25 15:13 cert.pem -> ../../archive/xxx.com/cert1.pem
      lrwxrwxrwx 1 root root 35 Sep 25 15:13 chain.pem -> ../../archive/xxx.com/chain1.pem
      lrwxrwxrwx 1 root root 39 Sep 25 15:13 fullchain.pem -> ../../archive/xxx.com/fullchain1.pem
      drwxr-xr-x 2 root root 4096 Sep 26 13:07 private.pem/
      lrwxrwxrwx 1 root root 37 Sep 25 15:13 privkey.pem -> ../../archive/xxx.com/privkey1.pem
      -rw-r--r-- 1 root root 682 Sep 25 15:13 README

具体验证机制
  • 验证的时候会自动向${webroot-path}/.well-known/acme-challenge目录下写一个临时文件,然后会发送一个请求,去验证是否可以正常访问,访问的请求类似下面

    1
    222.64.78.214 - - [26/Sep/2023:02:43:56 +0000] "GET /.well-known/acme-challenge/FHGV2yVHs0q5dJFXBGjWkwOcIqXlP9oNyy5srR4zGR8 HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" "-"
    • 使用Nginx方式配置如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      server {
      listen 80;
      server_name test.com;

      location ^~ /.well-known/acme-challenge/ {
      alias /var/www/challenges/;
      try_files $uri = 404;
      }
      location / {
      return 301 https://$host$request_uri;
      }
      }

standalone

  • 该插件会启动一个web服务器,使用--preferred-challenges http参数的话,对应使用80端口,使用--preferred-challenges tls-sni参数对应使用443端口.

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

DNS plugins

manual

  • 该方法允许你通过交互的方式获取证书,可以在其它服务器上运行,可以选择http,dnstls-sni方式中的任意一种。

  • 比如使用DNS的方式,会要求你在验证过程中手动填写TXT DNS的记录,然后继续,验证成功后会获取证书。

    1
    certonly  -d *.test.cn -d test.cn --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory 
  • 上面是手动的方式申请,中间需要人工干预,去DNS服务商填写TXT记录。还可以使用脚本帮助你完成一些验证,可以使用--manual-auth-hook--manual-cleanup-hook参数

Challenge Types

HTTP-01 challenge

  • 通过http-01请求验证,会向http://你的域名/.well-known/acme-challenge/发送一条请求

    • 使用Nginx方式,配置如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    server {
    listen 80;
    server_name test.com;

    location ^~ /.well-known/acme-challenge/ {
    alias /var/www/challenges/;
    try_files $uri = 404;
    }
    location / {
    return 301 https://$host$request_uri;
    }
    }
    • /usr/local/www目录下则存放对应的Token文件,如http://test.com/.well-known/acme-challenge/o9d5Q0lWljlO9ENwmuKwaukg9al1AQymWdW_Ww3gSng
  • 执行命令

    1
    certbot certonly --webroot --webroot-path /var/www/challenges -d test.com
  • HTTP-01验证最多接受 10 次重定向.只接受目标为http:https:且端口为 80 或 443 的重定向.不目标为 IP 地址的重定向.当被重定向到 HTTPS 链接时,不会验证证书是否有效(因为验证的目的是申请有效证书,所以它可能会遇到自签名或过期的证书)。

  • HTTP-01验证只能使用 80 端口.因为允许客户端指定任意端口会降低安全性,所以 ACME 标准已禁止此行为。

DNS-01 challenge

  • 通过dns-01解析,需要在域名解析中增加一条_acme-challenge.你的域名TXT记录用于验证

  • 执行命令

    1
    certbot certonly --preferred-challenges dns --manual  -d *.holelin.cn --server https://acme-v02.api.letsencrypt.org/directory

示例

使用docker+nginx+certbot方式配置证书

  • docker-compose.yaml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    version: '3.1'

    services:
    nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    - 443:443
    restart: always
    volumes:
    # Nginx配置文件
    - /root/nginx/conf.d:/etc/nginx/conf.d/:ro
    # Nginx日志文件
    - /root/nginx/logs:/usr/local/logs
    # http验证目录,可设置为只读(ro)
    - /root/nginx/www:/usr/local/www:ro
    # certbot生成的证书位置
    - /root/nginx/ssl:/etc/nginx/ssl:ro
    certbot:
    image: certbot/certbot:latest
    container_name: certbot
    volumes:
    # http验证目录,可设置rw可写,与nginx容器对应的宿主机目录时一致的
    - /root/nginx/www:/var/www/certbot:rw
    # 证书位置,同上,注意不要只映射到live,而是它的上一级
    - /root/nginx/ssl:/etc/letsencrypt/:rw
  • nginx的配置xxx.com.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    server {
    listen 80;
    server_name xxxx.com;
    #配置http验证可访问
    location ^~ /.well-known/acme-challenge/ {
    #此目录都是nginx容器内的目录,对应宿主机volumes中的http验证目录,而宿主机的又与certbot容器中命令--webroot-path指定目录一致,从而就整个串起来了,解决了http验证问题
    root /usr/local/www;
    }
    location / {
    return 301 https://$host$request_uri;
    }
    }
    server {
    listen 443 ssl;
    server_name xxx.com;

    error_log /usr/local/logs/error.log;
    access_log /usr/local/logs/access.log main;
    ssl_certificate /etc/nginx/ssl/live/xxx.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/xxx.com/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;

    location / {
    root /usr/local/xxx/test;
    index index.html;
    }

    }
    • 映射关系

      目录 certbot 宿主机 nginx
      http验证目录 /var/www/certbot /root/nginx/www /usr/local/www
      证书目录 /etc/letsencrypt /root/nginx/ssl /etc/nginx/ssl
  • 操作步骤

    1. 编写好docker-compose.yaml文件

    2. 执行

      1
      docker-compose -f docker-compose.yaml run --rm certbot certonly --webroot --webroot-path /var/www/certbot -d xxx.com
    3. 执行完成后,certbot生成证书的目录下live目录下就会有对应域名文件夹,文件夹中就有域名证书文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      # ll
      total 28
      drwxr-xr-x 7 root root 4096 Sep 26 14:21 ./
      drwxr-xr-x 8 root root 4096 Sep 26 14:12 ../
      drwx------ 3 root root 4096 Sep 26 14:12 accounts/
      drwx------ 3 root root 4096 Sep 26 14:13 archive/
      drwx------ 3 root root 4096 Sep 26 14:13 live/
      drwxr-xr-x 2 root root 4096 Sep 26 14:13 renewal/
      drwxr-xr-x 5 root root 4096 Sep 26 13:56 renewal-hooks/

      # ll live/xxx.com/
      total 12
      drwxr-xr-x 2 root root 4096 Sep 26 14:13 ./
      drwx------ 3 root root 4096 Sep 26 14:13 ../
      lrwxrwxrwx 1 root root 34 Sep 26 14:13 cert.pem -> ../../archive/xxx.com/cert1.pem
      lrwxrwxrwx 1 root root 35 Sep 26 14:13 chain.pem -> ../../archive/xxx.com/chain1.pem
      lrwxrwxrwx 1 root root 39 Sep 26 14:13 fullchain.pem -> ../../archive/xxx.com/fullchain1.pem
      lrwxrwxrwx 1 root root 37 Sep 26 14:13 privkey.pem -> ../../archive/xxx.com/privkey1.pem
      -rw-r--r-- 1 root root 692 Sep 26 14:13 README
    4. 修改配置Nginx文件

    5. 检查Nginx配置,重载配置

      1
      2
      3
      4
      # 检测配置nginx文件是否有问题
      docker-compose exec nginx nginx -t
      # 重载配置
      docker-compose exec nginx nginx -s reload
    6. 添加定时任务

      1
      2
      # 1、切换到docker-compose.yml所在目录;2、然后更新证书,只有距离过期时间30天内才会真正成功;3、然后重载nginx使新证书生效
      0 0 1,15 * * /usr/local/bin/docker-compose -f /home/xxxx/script/docker-compose.yaml run --rm certbot renew && /usr/local/bin/docker-compose exec nginx nginx -s reload