直接部署(不推荐)

安装 certbot

  • 在 alpine linux 中安装 certbot

    1
    
    apk add --no-cache certbot openssl
    
  • 注册

    1
    
    certbot register --register-unsafely-without-email --agree-tos
    

申请常规域名证书

  • 申请 ssl 证书,有效期 90 天

    1
    2
    3
    4
    5
    
    certbot certonly -n -d x.x.com --standalone
    
    # 证书文件生成到 /etc/letsencrypt/live/x.x.com/ 下
    # 参数 -d 可以使用多次来指定多个域名,也可以在一个 -d 参数中使用逗号分隔多个域名
    # 参数 --cert-name 可以指定证书文件的父级目录名字(替换默认的 x.x.com)
    
  • 续签 ssl 证书

    1
    
    cerbot renew --force-renewal
    
  • 生成 2048 位的交换密钥文件

    1
    
    openssl dhparam -out /etc/letsencrypt/dhparam.pem 2048
    

申请通配域名证书

  • 申请 ssl 证书,有效期 90 天

    1
    2
    3
    4
    5
    6
    7
    
    certbot certonly --manual -d '*.x.com' \
        --preferred-challenges dns \
        --server https://acme-v02.api.letsencrypt.org/directory
    
    # 按照提示,在对应的域名运营商平台新增或修改 _acme-challenge 记录的 txt 值
    # 证书文件生成到 /etc/letsencrypt/live/x.com/ 下
    # 参数 --cert-name 可以指定证书文件的父级目录名字(替换默认的 x.com)
    
  • 续签 ssl 证书,使用 certonly 子命令指定域名单独更新

    1
    2
    3
    4
    5
    
    certbot certonly --force-renewal --manual -d '*.x.com' \
        --preferred-challenges dns \
        --server https://acme-v02.api.letsencrypt.org/directory
    
    # 按照提示,在对应的域名运营商平台修改 _acme-challenge 记录的 txt 值
    
  • 生成 2048 位的交换密钥文件

    1
    
    openssl dhparam -out /etc/letsencrypt/dhparam.pem 2048
    

容器部署

申请常规域名证书

  • 为域名 x1.xx.com 和 x2.xx.com 申请 ssl 证书,创建 /letsencrypt/docker-compose.yml,内容如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    version: "3.7"
    services:
      letsencrypt-common:
        image: harbor.colben.cn/general/letsencrypt:latest
        container_name: letsencrypt-common
        restart: "no"
        stop_grace_period: 4s
        environment:
          DOMAINS: x1.xx.com,x2.xx.com
        network_mode: host
        volumes:
        - type: bind
          source: ./common/etc
          target: /etc/letsencrypt
        - type: bind
          source: ./common/log
          target: /var/log/letsencrypt
    
  • 创建目录

    1
    
    mkdir -p /letsencrypt/common/{etc,log}
    
  • 手动启动,等待容器停止后,证书申请完成

    1
    
    docker-compose up -d
    
  • 创建定时任务,在每月的 31 号晚上十一点更新一次

    1
    
    0 23 31 * * docker-compose -f /letsencrypt/docker-compose.yml up letsencrypt-common
    

申请通配域名证书

  • 为域名 *.xxx.com 和 *.yyy.com 申请 ssl 证书,创建 /letsencrypt/docker-compose.yml,内容如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    version: "3.7"
    services:
      letsencrypt-wildcard:
        image: harbor.colben.cn/general/letsencrypt
        container_name: letsencrypt-wildcard
        restart: "no"
        stop_grace_period: 1m
        environment:
          DOMAINS: "*.xxx.com,*.yyy.com"
        network_mode: host
        volumes:
        - type: bind
          source: ./wildcard/etc
          target: /etc/letsencrypt
        - type: bind
          source: ./wildcard/log
          target: /var/log/letsencrypt
    
  • 创建目录

    1
    
    mkdir -p /letsencrypt/wildcard/{etc,log}
    
  • 获取通配域名的证书时,需要设置 TXT 解析记录,这里配合脚本实现自动添加和更新

    • 调用腾讯云接口设置/更新 TXT 解析记录

      1
      2
      3
      4
      
      cp tencent-api.sh /letsencrypt/wildcard/etc/manual-hook.sh
      # 修改脚本,替换成自己的阿里云 access key 信息
      #ACCESS_KEY_ID='aliyun access key id'
      #ACCESS_KEY_SECRET='aliyun access key secret'
      
    • 调用阿里云接口设置/更新 TXT 解析记录

      1
      2
      3
      4
      
      cp aliyun-api.sh /letsencrypt/wildcard/etc/manual-hook.sh
      # 修改脚本,替换成自己的腾讯云 secret 信息
      #SECRET_ID='tencent secret id'
      #SECRET_KEY='tencent secret key'
      
  • 手动启动,等待容器停止后,证书申请完成

    1
    
    docker-compose up -d
    
  • 创建定时任务,并在每月的 31 号晚上十点更新一次

    1
    
    0 22 31 * * docker-compose -f /letsencrypt/docker-compose.yml up letsencrypt-wildcard
    

使用证书

  • nginx 配置 ssl
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    server {
        listen                    443 ssl http2;
        server_name               x.x.x; # 替换成自己的域名
        ssl_certificate           /letsencrypt/xxxx/etc/live/xxxx/fullchain.pem; # 替换实际目录
        ssl_certificate_key       /letsencrypt/xxxx/etc/live/xxxx/privkey.pem; # 替换实际目录
        ssl_session_cache         shared:le_nginx_SSL:10m;
        ssl_session_timeout       1440m;
        ssl_session_tickets       off;
        ssl_prefer_server_ciphers off;
        ssl_protocols             TLSv1.2 TLSv1.3;
        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";
        ssl_dhparam               /letsencrypt/xxxx/etc/dhparam.pem; # 替换实际目录
        location / {
            return 404;
        }
    }