在 Docker 中运行 acme.sh 为 Nginx 容器部署免费 SSL 证书

status
Published
type
Post
slug
run-acme.sh-to-deploy-free-ssl-cert-for-nginx-container-in-docker
date
May 28, 2024
tags
Docker
Config
Cloudflare
Share
Domain
summary
本文介绍了如何在 Docker 环境中使用 acme.sh 脚本为 Nginx 容器自动化部署免费的 SSL 证书,并且详细说明了配置记录、安装 acme.sh、签发证书以及部署证书的步骤。

前言

acme.sh 是一个 Unix Shell 脚本,实现了 ACME 客户端协议,支持自动化签发和更新免费证书。它支持 ECDSA 证书、SAN 和通配符证书,易于使用,无需 root 权限。
项目仓库中的各类说明已经较为全面,这里仅仅是针对我个人在 Docker 环境下使用时一些配置记录。

配置记录

安装 acme.sh

作为 Docker 爱好者,总是有点强迫症地想将一切操作都放在容器里隔离开来,不想在宿主机上处理,尽管只是一个单纯的 shell 脚本。如下为 docker compose 文件配置:
compose.yaml
services: acme-sh: image: neilpang/acme.sh container_name: acme.sh volumes: - ./acme-data:/acme.sh - /var/run/docker.sock:/var/run/docker.sock network_mode: host command: daemon stdin_open: true tty: true restart: no
docker compose up -d 执行即可运行起来,之后就可以使用 docker exec 来执行任何 acme.sh 命令了。
notion image

签发证书

  • Nginx 容器配置
首先要为 Nginx 容器增加一个 label: sh.acme.autoload.domain=okhk.net,其中 okhk.net 就是将要为之签发的域名,如下为 Nginx 容器 compose 文件修改后的内容:
services: nginx: image: nginx:alpine container_name: nginx restart: always network_mode: host volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./nginx/ssl:/etc/nginx/ssl - ./nginx/conf:/etc/nginx/conf.d environment: TZ: Asia/Shanghai labels: - sh.acme.autoload.domain=okhk.net
 
  • Cloudflare API Token
因为我的域名托管在 Cloudflare 上,要想通过 DNS 签发证书,需要先获取 Cloudflare 平台的 API Token。
💡
不建议使用 Global API Key !!!
API Token是一个40个字符的字符串,可能包含大写字母、小写字母、数字和下划线。
在 Cloudflare Dashboard 个人资料页面的 API Tokens 部分,点击 Create Token
notion image
可以直接选用具有 DNS 编辑权限的模板
notion image
notion image
选中你想要签发证书的域名,还可以配置 IP 地址过滤增强安全性,各项配置无误后点击继续。
notion image
将这里生成的 API Token 保存下来(如未保存遗失后只能重新创建),后面会用到。
打开对应域名的概览页面,在右侧栏靠下方获取对应 Zone ID 以及 Account ID ,同样记录下来。
notion image
 
  • 签发证书
执行如下命令
docker exec \ -e CF_Token=[替换为前面获取的 API Token ] \ -e CF_Account_ID=[ 替换为前面获取的 Account ID ] \ -e CF_Zone_ID=[ 替换为前面获取的 Zone ID ] \ acme.sh --issue -d okhk.net --dns dns_cf
报错如下:
notion image
注册账户执行命令:
docker exec acme.sh --register-account -m ssl@okhk.net --server zerossl
之后再重新执行👆上面的签发命令。
 
  • 部署证书
执行命令:
docker exec \ -e DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=okhk.net \ -e DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/nginx/ssl/okhk.net/key.pem \ -e DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/ssl/okhk.net/cert.pem" \ -e DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/ssl/okhk.net/ca.pem" \ -e DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/ssl/okhk.net/full.pem" \ -e DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload" \ acme.sh --deploy -d okhk.net --deploy-hook docker
最终提示 Success 即已经成功将证书安装到指定路径了,只需要 Nginx 的 conf 配置中路径对应上即可,可按需修改。
Nginx 的配置 ssl_certificate 使用 /etc/nginx/ssl/fullchain.cer ,而非 /etc/nginx/ssl/<domain>.cer ,否则 SSL Labs 的测试会报 Chain issues Incomplete 错误。
 
最终 acme.sh 的容器 compose 配置如下:
compose.yaml
services: acme-sh: image: neilpang/acme.sh container_name: acme.sh volumes: - ./acme-data:/acme.sh - /var/run/docker.sock:/var/run/docker.sock network_mode: host command: daemon stdin_open: true tty: true restart: no environment: - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=okhk.net - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/nginx/ssl/okhk.net/key.pem - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/ssl/okhk.net/cert.pem" - DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/ssl/okhk.net/ca.pem" - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/ssl/okhk.net/full.pem" - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"
 
配置完成后检测一下
notion image