在docker中使用nginx,并在nginx容器中使用acme.sh自动续签证书,本文中使用CloudFlare的dns验证进行自动续签。
因为默认docker nginx镜像中没有cron,但acme的自动续签功能又依赖于cron,所以只能在此之上构建一个带cron的docker镜像。
编写dockerfile
nano ./dockerfile
# 以nginx镜像为基础镜像
FROM nginx:latest
# 更新软件包并安装 cron 和 curl(虽然nginx镜像已经包含curl了)
RUN apt-get update && apt-get install -y cron curl && \
curl https://get.acme.sh | sh
# 定义启动命令,启动cron和nginx
CMD ["sh", "-c", "cron & nginx -g 'daemon off;'"]
构建镜像
注意:过程需要连接到get.acme.sh和apt-get源,docker源,请保持网络通畅。
docker build -t nginx-acme -f dockerfile .
配置docker compose
使用刚才构建好的镜像nginx-acme
mkdir nginx-acme && cd nginx-acme
nano ./docker-compose.yaml
services:
nginx:
image: nginx-acme
network_mode: "host"
volumes:
- ./ssl:/file/ssl
- ./nginx.conf:/etc/nginx/nginx.conf
- ./account.conf:/root/.acme.sh/account.conf
restart: always
command: ["tail", "-f", "/dev/null"]
创建nginx.conf文件,用于映射进容器来配置nginx,证书路径填/file/ssl/cert.pem,私钥路径填/file/ssl/key.pem
nano ./nginx.conf
……
listen 443 ssl;
#证书路径填/file/ssl/cert.pem
ssl_certificate /file/ssl/cert.pem;
#私钥路径填/file/ssl/key.pem
ssl_certificate_key /file/ssl/key.pem;
……
创建account.conf文件,用于映射进容器来配置acme.sh
nano ./account.conf
#LOG_FILE="/root/.acme.sh/acme.sh.log"
#LOG_LEVEL=1
#AUTO_UPGRADE="1"
#NO_TIMESTAMP=1
ACCOUNT_EMAIL="填邮箱"
CF_Token="填cloudflare的token"
CF_Zone_ID="填cloudflare区域id"
CF_Account_ID="填cloudflare的账户id"
CERT_HOME="/file/ssl"
Le_Challenge_Type="dns-01"
USER_PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
配置好之后,直接启动docker compose服务手动申请证书一次,否则nginx会报错找不到证书文件。
docker compose up -d
申请测试证书
进入容器测试申请证书是否成功(使用docker ps查看nginx-acme容器id)
docker exec -it [nginx-acme容器id] /bin/bash
申请测试证书(仅临时测试用,不受信任)命令:
/root/.acme.sh/acme.sh --issue --staging -d "域名" --dns dns_cf --key-file /file/ssl/key.pem --cert-file /file/ssl/cert.pem
申请测试证书成功后就可以退出并关掉docker compose服务,并删掉./ssl 里面所有的文件。
exit
docker compose down
rm -rf ./ssl/*
启动服务
然后改一下 docker-compose.yaml,让其正常启动nginx和cron( 删掉最后一行,也就是command: ["tail", "-f", "/dev/null"] )
services:
nginx:
image: nginx-acme
network_mode: "host"
volumes:
- ./ssl:/file/ssl
- ./nginx.conf:/etc/nginx/nginx.conf
- ./account.conf:/root/.acme.sh/account.conf
restart: always
启动docker compose服务
docker compose up -d
进入容器申请证书
docker exec -it [nginx-acme容器id] /bin/bash
申请普通证书命令:
/root/.acme.sh/acme.sh --issue -d "域名" --dns dns_cf --key-file /file/ssl/key.pem --cert-file /file/ssl/cert.pem --reloadcmd "nginx -s reload"
成功申请后即可exit
退出,证书到期时cron会自动运行acme.sh实现续签,并执行nginx -s reload
重载nginx配置文件更新证书。
最终文件目录
.
|-- docker-compose.yaml
|-- account.conf
|-- nginx.conf
`-- ssl
|-- *.domain_ecc
| |-- *.domain.cer
| |-- *.domain.conf
| |-- *.domain.csr
| |-- *.domain.csr.conf
| |-- *.domain.key
| |-- backup
| |-- ca.cer
| `-- fullchain.cer
|-- cert.pem
`-- key.pem
不需要担心容器被还原后自动续期失效,因为已经把acme.sh的配置文件account.conf映射到容器内,而且证书安装路径、nginx重载指令等配置都保存在./ssl/domain/domain.conf。