docker 方式使用 acme.sh(SSL 证书自动续期)

1,786 阅读4分钟

ACME 是什么

acme.sh 是一款可以为我们的服务自动申请 SSL 证书的工具。传统方式申请证书的流程一般如下:

  1. 在网站(比如:freessl.cn/)申请。
  2. 到域名服务商添加 DNS 解析,或在自己服务器上放校验文件。
  3. 等待 SSL 签发商(比如:Let's Encrypt 与 TrustAsia)验证,一般半小时内验证完成。
  4. 下载证书并部署到自己的服务器上。

证书一般是几个月或一年有效期,每次都手动搞一下也挺烦。而且如果有多个子域名操作就更多了,自动工具可以帮你定期做这些事情。

部署

直接安装

可以将工具直接安装在服务器上,个人觉得这样很麻烦,需要装依赖的包还对服务器造成了“污染”。有兴趣的可以了解一下 github.com/acmesh-offi…

Docker 安装

安装并运行neilpang/acme.sh镜像,这里是以daemon方式安装,这样,就可以像运行一个命令一样使用 acme.sh 了。

下面的例子是以 Namesilo 为DNS服务商,采用DNS验证的方式:

docker run --rm -itd \
    -v "$(pwd)/out":/acme.sh \ # 最终的产物将放在这里
    -e Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxxx" \ # 在Namesilo后台创建的api key
    --net=host \
    --name=acme.sh \
    neilpang/acme.sh daemon
  1. 最重要的是 -e Namesilo_Key="xxxxxxxxxxxxxxxxxxxxxxxxx" 这一行,不同的服务商对应环境变量的key和数量都不一样,具体支持的列表在这里 image.png

  2. 这个Namesilo_Key 值从哪里来呢,从各个厂商的管理后来创建,我这里以Namesilo 为例。image.png image.png image.png

运行

申请

先运行下面这个命令,意思是提出申请,具体注释也写上了。

    docker exec acme.sh \
        --issue \
        --dns dns_namesilo \ # 指定DNS服务商
        --dnssleep 1800 \ # 1800s 后到域名提供商验证txt_name
        -d wanghl.cc \ # 需要申请的域名
        -d www.wanghl.cc \ # 需要申请的域名
        -d qingdu.wanghl.cc \ # 需要申请的域名
        -d lib.wanghl.cc \ # 需要申请的域名
        -d media.wanghl.cc \ # 需要申请的域名
        --server letsencrypt \ # 从 letsencrypt 申请证书
        --yes-I-know-dns-manual-mode-enough-go-ahead-please
  1. dns_namesilo 表示你用的是哪家域名提供商,具体支持列表还是在这里,例如下图: image.png
  2. -d 表示需要申请证书的域名,可以一次加入多个。
  3. --server 表示从哪个申请证书,letsencrypt 简单一些,如果不加这一行,默认会从ZeroSSL.com CA申请。需要注意的是,如果你从ZeroSSL.com CA申请,需要更多信息,本套教程对你来说就不完整了。

RENEW

上面的命令执行完以后,可以用下面的命令生成证书,你可以理解为轮询结果。

    docker exec acme.sh \
        --renew \
        --dns dns_namesilo \ # 指定DNS服务商
        --dnssleep 1800 \
        -d wanghl.cc \ # 需要申请的域名
        -d www.wanghl.cc \ # 需要申请的域名
        -d qingdu.wanghl.cc \ # 需要申请的域名
        -d lib.wanghl.cc \ # 需要申请的域名
        -d media.wanghl.cc \ # 需要申请的域名
        --server letsencrypt \ # 从 letsencrypt 申请证书
        --log \ # 输出日志文件
        --yes-I-know-dns-manual-mode-enough-go-ahead-please

这个命令看上去跟上面的很像,值得注意的参数有下面几个:

  1. -renew : 把上面命令中的--issue 换成了这个,表示刷新证书有效期。
  2. --dnssleep :表示多长时间轮询一次,DNS生效需要时间,一般在半小时(1800s)以内,你也可以设小一点。
  3. --log 生成日志文件,不管成功/失败,你都可以在日志中看到详细信息。比如脚本做了哪些事、报了什么错,建议加上。

如果DNS验证没有通过,也就是DNS还没有生效,脚本会卡住,在--dnssleep 后再次轮询,直到成功。成功截图如下: image.png

正如上图中显示的,会在out 目录生成几个文件。对我来说有用的文件有两个fullchan.cerwanghl.cc.key

KONG 中更新证书

我是用KONG 做的网关,这里顺带也说一下操作方法,其他的比如 Nginx / Apache 操作方法自行google了。 image.png

自动部署证书

上面一步更新证书文件也是可以自动化的,具体没有研究了,可以看这里 image.png

相当于帮你把证书放到指定的地方,再帮你重启一下Nginx。

自动部署到kong

可以把 fullchan.cerwanghl.cc.key 两个文件拷到 kong 的 ssl 目录里。

下面是我kong的一段docker-compose,KONG_SSL_CERT 和 KONG_SSL_CERT_KEY 两个环境变量指向kong的默认证书。

kong:
    image: kong
    container_name: kong
    volumes:
      - "./ssl:/mnt/ssl"
    environment:
      - LC_CTYPE=en_US.UTF-8
      - LC_ALL=en_US.UTF-8
      - KONG_DATABASE=postgres
      - KONG_PG_HOST=kong-database
      - KONG_PG_USER=kong
      - KONG_PG_PASSWORD=xxxxxxxxxxxxxxxxxxx
      - KONG_CASSANDRA_CONTACT_POINTS=kong-database
      - KONG_PROXY_ACCESS_LOG=/dev/stdout
      - KONG_ADMIN_ACCESS_LOG=/dev/stdout
      - KONG_PROXY_ERROR_LOG=/dev/stderr
      - KONG_ADMIN_ERROR_LOG=/dev/stderr
      - KONG_SSL_CERT=/mnt/ssl/fullchain.cer
      - KONG_SSL_CERT_KEY=/mnt/ssl/wanghl.cc.key
      - KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl

我把上面**运行** 章节中的所有操作写在了一个shell中,现在我在这个shell中加如下操作:

# 复制证书到kong
cp -r ./out/wanghl.cc_ecc/fullchain.cer ./out/wanghl.cc_ecc/wanghl.cc.key ../kong/ssl
# 加可读权限
chmod a+r ../kong/ssl/wanghl.cc.key
# 重启kong
docker compose -f ../kong/docker-compose.yml restart

至此,可以实现自动化更新SSL证书了。当然想要全自动的话,再加一个定时任务就行了,定时任务可以用Cronicle,看我这篇