容器部署 Nginx 并使用 ACME.sh 自动配置 TLS

ACME.sh 也算是把证书签发这件小事做得相当完善,但他们的文档不是很好查,每次部署都得确认一些细节,因此做个备忘。

Nginx 部分没有什么好说:

services:
  nginx:
    image: nginx:alpine
    container_name: nginx
    restart: always
    depends_on:
      - xxx #我习惯放在 Web 应用后面启动
    volumes:
      - ~/nginx/conf.d:/etc/nginx/conf.d #自定义用,如果只是 https 甚至都可以不需要
      - ~/nginx/logs:/var/log/nginx #收集日志还是有必要的
      - ~/nginx/ssl:/etc/nginx/ssl #一探究竟用,其实用不着
    ports:
      - "443:443"
      - "80:80"
    labels:
      - "sh.acme.autoload.domain=example.com" #重要,acme.sh 靠这个来定位 Nginx 的容器

重点是 ACME.sh 的部分:

services:
#前提是 nginx 的 labels 得在
  acme.sh:
    image: neilpang/acme.sh
    container_name: acme.sh    
    command: daemon
    volumes:
      - ./acmeout:/acme.sh
      - /var/run/docker.sock:/var/run/docker.sock 
    environment:
      #部署到 Nginx 容器用,纯纯复制粘贴就行
      - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=example.com
      - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/nginx/ssl/example.com/key.pem
      - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/ssl/example.com/cert.pem"
      - DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/ssl/example.com/ca.pem"
      - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/ssl/example.com/full.pem"
      - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"

都运行起来后回到宿主机,用 ACME.sh 容器运行它的脚本。都可以用,这里用 CloudFlare API 签发举例:

docker exec \
    -e [email protected] \
    -e CF_Key=xxxxxxxxxx  \
    acme.sh --issue -d example.com  --dns dns_cf  \
    --server letsencrypt

最后一个参数是因为 ACME.sh 默认已经换成了 ZeroSSL,可能有技术考虑,但更多应该是赞助。如果要继续用 Let's Encrypt,得额外指定一下。

证书成功签发后,可以自动或手动部署到 Nginx 去:

docker exec acme.sh --deploy -d example.com  --deploy-hook docker

几条 docker 命令的 -e 参数都可以和 compose 文件里的环境变量相互替换,我觉得自用的话可能一股脑全扔进 compose 文件(敏感字段放在同目录的 .env 文件并且记得在 Git 里忽略)比较合适,这里就不写得那么花哨了。

然后 ACME.sh 就已经帮你做完了所有事,包括监听 443 端口、部署证书和重载 Nginx 配置。也就是说,你就算是个崭新的 Nginx 容器,没有配置任何站点,到这里也可以直接使用 https 访问刚才签发的域名了。

其实操作上官方文档说得非常清楚,但对具体做了什么少了点描述,希望这是一个还算有用的补充。

添加新评论