容器化freessl-acme.sh更新nginx实现https证书自动续期:修订间差异

来自三线的随记
(创建页面,内容为“先构建一个 acme.sh 基础镜像 cat <<\EOF > acme.sh.Dockerfile FROM alpine:3.15.3 RUN apk --no-cache add curl wget openssl && \ rm -rf /var/cache/apk &…”)
 
(调整nginx和acme.sh容器编排顺序)
 
(未显示同一用户的20个中间版本)
第1行: 第1行:
先构建一个 acme.sh 基础镜像
=== 赘述 ===
由于有一定的OS环境洁癖,所以不打算直接在Linux OS环境中直接安装acme.sh,采用容器化的方式安装acme.sh
 
acme.sh官方其实有做好的docker images,但是由于太闲了所以又重新写了一份(班门弄斧)
 
=== 正题1: 制作能自签域名证书的镜像 ===
先构建一个带有 acme.sh 基础镜像
  cat <<\EOF > acme.sh.Dockerfile
  cat <<\EOF > acme.sh.Dockerfile
  FROM alpine:3.15.3
  FROM alpine:3.15.3
第6行: 第12行:
     curl -s <nowiki>https://get.acme.sh</nowiki> | sh -s [email protected]
     curl -s <nowiki>https://get.acme.sh</nowiki> | sh -s [email protected]
  WORKDIR /root/.acme.sh
  WORKDIR /root/.acme.sh
ENTRYPOINT ["/usr/sbin/crond", "-f", "-S","/dev/stdout"]
  EOF
  EOF


  docker build -f acme.sh.Dockerfile -t sanxian/freessl_acme.sh_base:v1 .
  docker build -f acme.sh.Dockerfile -t san3xian/freessl_acme.sh:v2 .
<nowiki/>https://freessl.cn/acme-deploy 登陆并添加域名,获取token
然后到<nowiki/>https://freessl.cn/acme-deploy 注册登陆
  FROM sanxian/freessl_acme.sh_base:v1
 
  ARG  acme_token="your_token"
并在该站点的 [https://freessl.cn/acme-deploy acme页面中]添加域名,完成域名的DCV预检测(即配置CNAME,域名解析状态可以在这里查询: https://myssl.com/dns_check.html)
ENV  acme_domain="your_domain"
 
获取token (即ACME 地址中 ****/directory/ 后的字符串)
 
接着根据实际需求构建域名专属acme镜像用于签发证书,安装证书以及触发 容器化或者节点直接部署运行的nginx reload(后面按需运行的时候修改该容器pid mode和reloadcmd即可)
 
这里 <code>--issue</code> 命令中由于没有带--days参数,所以默认签的是60天的证书
 
将下述内容按需修改存于Dockerfile中
  FROM san3xian/freessl_acme.sh:v2
  ARG  acme_token="your_token" \
      acme_domain="your_domain"
  RUN /root/.acme.sh/acme.sh --issue -d ${acme_domain}  --dns dns_dp \
  RUN /root/.acme.sh/acme.sh --issue -d ${acme_domain}  --dns dns_dp \
     --server <nowiki>https://acme.freessl.cn/v2/DV90/directory/${acme_token}</nowiki> && \
     --server <nowiki>https://acme.freessl.cn/v2/DV90/directory/${acme_token}</nowiki> && \
     mkdir -pv /cert
     mkdir -pv /certs && \
ENTRYPOINT ["/bin/sh", "-c", "/root/.acme.sh/acme.sh --install-cert \
    /root/.acme.sh/acme.sh --install-cert -d ${acme_domain} \
            -d ${acme_domain} \
    --key-file /certs/${acme_domain}_key.pem \
            --key-file /certs/${acme_domain}_key.pem \
    --fullchain-file /certs/${acme_domain}_cert.pem \
            --fullchain-file /certs/${acme_domain}_cert.pem \
    --reloadcmd "/bin/kill -s HUP 1"
            --reloadcmd \"/bin/kill -s HUP 1\" && sleep infinity"]
使用docker build构建镜像
docker build -t san3xian/freessl_acme.sh:yourdomain .
如果上述步骤都没错的话,在构建这个带有域名证书信息的镜像的时候,就能看到申请下来的证书会被打印输出到控制台
 
并且根据回显内容可知,申请下来的证书保存在了 <code>/root/.acme.sh/${acme_domain}/</code> 路径下,而且证书会被拷贝一份到 <code>/certs</code> 路径下(此路径按实际需求在Dockerfile中修改即可)
 
在freessl.cn的acme页面中也能看到相应的客户端ID信息
 
证书的相关配置信息(如install-path和ReloadCmd)在<code>/root/.acme.sh/${acme_domain}/${acme_domain}.conf</code> 文件中
 
到这里acme.sh自动签证书的步骤就已经基本做完了
 
acme.sh配置参考: https://blog.freessl.cn/acme-quick-start/
 
 
=== 正题2: 适配实际的tls证书使用环境 ===
如前所述,本文是为了用容器化的freessl acme.sh向容器化的nginx进行证书自签,所以下面还会有docker-compose的内容,当然实际操作中用docker run 直接运行容器也可以
 
前提展开: 由于我这里nginx容器是使用常规镜像启动的,所以我的nginx master的pid在容器的PID namespace就会是1,遂在上文的reloadcmd 中写死了pid
 
然后我的docker-compose.yml是在server文件夹下的,所以docekr-compose拉起的容器默认会带 <code>server_</code> 前缀,即如docker-compose help中所述:
docker-compose --help
  -p, --project-name NAME    Specify an alternate project name
                              (default: directory name)
docker-compose.yml内容,部分内容按实际需求修改
version: "2"
services:
  nginx:
    restart: always
    image: nginx:1.21-alpine
    volumes:
      - "/var/lib/nginx/conf.d:/etc/nginx/conf.d"
      - "/var/lib/nginx/nginx.conf:/etc/nginx/nginx.conf"
      - "/var/lib/nginx/certs:/etc/nginx/certs"
      - "/var/lib/nginx/sites-enabled:/etc/nginx/sites-enabled"
    ports:
      - "80:80" # http port for private network
      - "443:443" # https port for private network
  freessl:
    restart: always
    image: san3xian/freessl_acme.sh:yourdomain #修改为你在上文实际打出来的容器镜像
    volumes:
    - "/var/lib/nginx/certs:/certs"
    tty: true # alpine下不分配伪tty的话BusyBox crond会有的日志不输出到stdout
    pid: container:server_nginx_1 # 与nginx共享同一个PID namespace, 这里暂时没有找到在docker-compose文件中关联其它container的写法,所以只能完全写死容器名了
可见freessl 和 nginx 容器都挂载了同一个/var/lib/nginx/certs目录,这样nginx就能读到由freessl acme.sh自签下发的tls证书
 
接着docker-compose up -d 启动了相应的容器后
 
由于在前文签证书的时候,freessl acme.sh容器中/certs路径还没挂载到节点上,所以此时还需要重新拷贝/签一份证书到certs路径下
docker exec server_freessl_1 "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" --force
如果上述步骤都没错的话,此时nginx也会被触发reload,可以docker logs server_nginx_1 看相关信息,按照实际修改nginx的配置以让tls证书生效即可
 
由于freessl acme.sh容器中还有crond的守护进程运行着,所以acme.sh也会被定时触发,可以通过docker logs server_freessl_1看相关日志


crontab -l 也可以看到相关任务定时触发配置信息,建议按需将acme.sh触发命令的重定向( <code>> /dev/null</code> )去除以方便查看acme.sh的cron日志
[root@localhost server]# docker exec server_freessl_1 crontab -l
# do daily/weekly/monthly maintenance
# min hour day month weekday command
*/15 * * * * run-parts /etc/periodic/15min
0 * * * * run-parts /etc/periodic/hourly
0 2 * * * run-parts /etc/periodic/daily
0 3 * * 6 run-parts /etc/periodic/weekly
0 5 1 * * run-parts /etc/periodic/monthly
1 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null


<nowiki>#</nowiki> todo
如果需要添加多个域名的话,可以直接在freessl容器中运行命令
[[分类:Todo]]
/root/.acme.sh/acme.sh --issue -d ${acme_domain}  --dns dns_dp --server <nowiki>https://acme.freessl.cn/v2/DV90/directory/${acme_token}</nowiki>
/root/.acme.sh/acme.sh --install-cert -d ${acme_domain} --key-file /certs/${acme_domain}_key.pem --fullchain-file /certs/${acme_domain}_cert.pem --reloadcmd "/bin/kill -s HUP 1"
即可,这样下一次acme.sh的cron任务触发的时候,多个域名都会被执行证书更新检查
[[分类:Linux]]
[[分类:Linux]]
[[分类:Docker]]
[[分类:Docker]]
[[分类:Docker-compose]]
[[分类:Docker-compose]]
{{DEFAULTSORT:docker容器化freessl_acme.sh配合nginx实现https证书自动续期}}
{{DEFAULTSORT:docker容器化freessl_acme.sh配合nginx实现https证书自动续期}}

2022年4月5日 (二) 22:49的最新版本

赘述

由于有一定的OS环境洁癖,所以不打算直接在Linux OS环境中直接安装acme.sh,采用容器化的方式安装acme.sh

acme.sh官方其实有做好的docker images,但是由于太闲了所以又重新写了一份(班门弄斧)

正题1: 制作能自签域名证书的镜像

先构建一个带有 acme.sh 基础镜像

cat <<\EOF > acme.sh.Dockerfile
FROM alpine:3.15.3
RUN apk --no-cache add curl wget openssl && \
    rm -rf /var/cache/apk && \
    curl -s https://get.acme.sh | sh -s [email protected]
WORKDIR /root/.acme.sh
ENTRYPOINT ["/usr/sbin/crond", "-f", "-S","/dev/stdout"]
EOF
docker build -f acme.sh.Dockerfile -t san3xian/freessl_acme.sh:v2 .

然后到https://freessl.cn/acme-deploy 注册登陆

并在该站点的 acme页面中添加域名,完成域名的DCV预检测(即配置CNAME,域名解析状态可以在这里查询: https://myssl.com/dns_check.html)

获取token (即ACME 地址中 ****/directory/ 后的字符串)

接着根据实际需求构建域名专属acme镜像用于签发证书,安装证书以及触发 容器化或者节点直接部署运行的nginx reload(后面按需运行的时候修改该容器pid mode和reloadcmd即可)

这里 --issue 命令中由于没有带--days参数,所以默认签的是60天的证书

将下述内容按需修改存于Dockerfile中

FROM san3xian/freessl_acme.sh:v2

ARG  acme_token="your_token" \
     acme_domain="your_domain"
RUN /root/.acme.sh/acme.sh --issue -d ${acme_domain}  --dns dns_dp \
    --server https://acme.freessl.cn/v2/DV90/directory/${acme_token} && \
    mkdir -pv /certs && \
    /root/.acme.sh/acme.sh --install-cert -d ${acme_domain} \
    --key-file /certs/${acme_domain}_key.pem \
    --fullchain-file /certs/${acme_domain}_cert.pem \
    --reloadcmd "/bin/kill -s HUP 1"

使用docker build构建镜像

docker build -t san3xian/freessl_acme.sh:yourdomain .

如果上述步骤都没错的话,在构建这个带有域名证书信息的镜像的时候,就能看到申请下来的证书会被打印输出到控制台

并且根据回显内容可知,申请下来的证书保存在了 /root/.acme.sh/${acme_domain}/ 路径下,而且证书会被拷贝一份到 /certs 路径下(此路径按实际需求在Dockerfile中修改即可)

在freessl.cn的acme页面中也能看到相应的客户端ID信息

证书的相关配置信息(如install-path和ReloadCmd)在/root/.acme.sh/${acme_domain}/${acme_domain}.conf 文件中

到这里acme.sh自动签证书的步骤就已经基本做完了

acme.sh配置参考: https://blog.freessl.cn/acme-quick-start/


正题2: 适配实际的tls证书使用环境

如前所述,本文是为了用容器化的freessl acme.sh向容器化的nginx进行证书自签,所以下面还会有docker-compose的内容,当然实际操作中用docker run 直接运行容器也可以

前提展开: 由于我这里nginx容器是使用常规镜像启动的,所以我的nginx master的pid在容器的PID namespace就会是1,遂在上文的reloadcmd 中写死了pid

然后我的docker-compose.yml是在server文件夹下的,所以docekr-compose拉起的容器默认会带 server_ 前缀,即如docker-compose help中所述:

docker-compose --help 
 -p, --project-name NAME     Specify an alternate project name
                              (default: directory name)

docker-compose.yml内容,部分内容按实际需求修改

version: "2"

services:
  nginx:
    restart: always
    image: nginx:1.21-alpine
    volumes:
      - "/var/lib/nginx/conf.d:/etc/nginx/conf.d"
      - "/var/lib/nginx/nginx.conf:/etc/nginx/nginx.conf"
      - "/var/lib/nginx/certs:/etc/nginx/certs"
      - "/var/lib/nginx/sites-enabled:/etc/nginx/sites-enabled"
    ports: 
      - "80:80" # http port for private network
      - "443:443" # https port for private network
  freessl:
    restart: always
    image: san3xian/freessl_acme.sh:yourdomain #修改为你在上文实际打出来的容器镜像
    volumes:
    - "/var/lib/nginx/certs:/certs"
    tty: true # alpine下不分配伪tty的话BusyBox crond会有的日志不输出到stdout
    pid: container:server_nginx_1 # 与nginx共享同一个PID namespace, 这里暂时没有找到在docker-compose文件中关联其它container的写法,所以只能完全写死容器名了

可见freessl 和 nginx 容器都挂载了同一个/var/lib/nginx/certs目录,这样nginx就能读到由freessl acme.sh自签下发的tls证书

接着docker-compose up -d 启动了相应的容器后

由于在前文签证书的时候,freessl acme.sh容器中/certs路径还没挂载到节点上,所以此时还需要重新拷贝/签一份证书到certs路径下

docker exec server_freessl_1 "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" --force

如果上述步骤都没错的话,此时nginx也会被触发reload,可以docker logs server_nginx_1 看相关信息,按照实际修改nginx的配置以让tls证书生效即可

由于freessl acme.sh容器中还有crond的守护进程运行着,所以acme.sh也会被定时触发,可以通过docker logs server_freessl_1看相关日志

crontab -l 也可以看到相关任务定时触发配置信息,建议按需将acme.sh触发命令的重定向( > /dev/null )去除以方便查看acme.sh的cron日志

[root@localhost server]# docker exec server_freessl_1 crontab -l
# do daily/weekly/monthly maintenance
# min	hour	day	month	weekday	command
*/15	*	*	*	*	run-parts /etc/periodic/15min
0	*	*	*	*	run-parts /etc/periodic/hourly
0	2	*	*	*	run-parts /etc/periodic/daily
0	3	*	*	6	run-parts /etc/periodic/weekly
0	5	1	*	*	run-parts /etc/periodic/monthly

1 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

如果需要添加多个域名的话,可以直接在freessl容器中运行命令

/root/.acme.sh/acme.sh --issue -d ${acme_domain}  --dns dns_dp --server https://acme.freessl.cn/v2/DV90/directory/${acme_token}

/root/.acme.sh/acme.sh --install-cert -d ${acme_domain} --key-file /certs/${acme_domain}_key.pem --fullchain-file /certs/${acme_domain}_cert.pem --reloadcmd "/bin/kill -s HUP 1"

即可,这样下一次acme.sh的cron任务触发的时候,多个域名都会被执行证书更新检查