docker中使用acme.sh

Wen 发布于 2025-01-17 4526 次阅读


背景

原先服务器中,blog的ssl证书也是由acme.sh申请的,不过为了新服务器贯彻docker化的策略,acme.sh也实行docker化,并且官方这边也有docker容器

概况

根据这篇的说明deploy to docker containers就可以把证书部署到另一个容器中,但里面与配置没有说明多域名的情况下该如何实现。

所以我采取的是把输出的ssl证书文件路径,同时映射给nginx与acme.sh,这样的做法可能在证书更替期间,nginx没有重启,导致依旧使用旧ssl证书的情况,这个问题之后再说吧

然后是ssl证书签发的验证,则是采取http验证,为nginx和acme.sh创建个数据卷作为网站的根目录

大概流程如下:
1. acme.sh和nginx容器的启动
2. nginx中网站htpp配置编写
3. 申请ssl证书
4. https添加

acme.sh和nginx容器启动

使用docker-compose.yml部署这两个容器

services:
  web:
    image: nginx:alpine
    volumes:
     - ./config/conf.d:/etc/nginx/conf.d
     - ./config/nginx.conf:/etc/nginx/nginx.conf
     - html_file:/etc/nginx/html
     - ./ssl:/etc/nginx/ssl
    ports:
     - "80:80"
     - "443:443"

  acme-sh:
    image: neilpang/acme.sh
    container_name: acme.sh
    volumes:
      - ./ssl:/acme.sh
      - html_file:/html
    command: daemon
    stdin_open: true
    tty: true
    restart: no
volumes:
  html_file:

网站的访问统一由nginx来管理,所以只有nginx映射了宿主机的端口。
这里我同时映射了nginx中的nginx.conf文件和conf.d文件夹到宿主机,这里面的nginx.conf文件和conf.d内的default.conf文件我们可以简单启动一个临时nginx容器复制出来
docker-compose.yml目录下使用这个指令

docker run --rm -v $PWD/config:/config nginx cp -r /etc/nginx/nginx.conf /etc/nginx/conf.d /config

目录下的config文件夹内就是我们所需文件,这些文件路径在docker-compose.yml也是正确对应的,这就是为什么在docker-compose.yml文件目录下使用这个指令的原因

docker compose up -d

http文件编写

由于是使用http验证,需要写好域名的配置才能正常验证。
acme.sh使用http验证时,会是往网站根目录放一个存有key的文件来给ssl证书签发机构验证的,这个文件位置我们可以通过acme.sh的源码中查看到或者log文件(需要先执行申请ssl证书)中查看到
这位置是.well-known/acme-challenge

我们简单写一个http的nginx配置来让我们通过http验证

server {
    listen 80;
    listen [::]:80;
    server_name your.example.com;

    location /.well-known/acme-challenge {
        # 这里的路径对应好数据卷挂载的路径
        root /etc/nginx/html;
    }
}

保存这内容到文件,文件最好以域名命名your.example.com.conf
因为nginx内的conf.d文件夹也映射到宿主机,所以,直接放到对应目录即可,这里是./config/conf.d,放好后直接重启nginx容器即可

docker restart nginx容器ID

ssl证书申请

万事具备,使用以下指令申请,记得添加域名DNS记录指向服务器IP

docker exec acme.sh --issue -d your.example.com -w /html

使用后可能会要求添加邮箱地址,按要求添加即可
指令最后的/html是与acme.sh容器挂载html_file数据卷对应的路径,别写错,写错验证过不了
如无意外,ssl证书就能正常签发下来,证书存在容器内的/acme.sh文件夹内,并且以域名文件夹区分,我们这里直接映射这个目录

https添加

acme.sh容器申请的证书文件夹我们直接映射到宿主机,这些文件也映射到了nginx容器内的/etc/nginx/ssl,所以我们直接读取这些文件即可
以下是修改后的配置文件

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate       /etc/nginx/ssl/your.example.com_ecc/your.example.com.cer;
    ssl_certificate_key   /etc/nginx/ssl/your.example.com_ecc/your.example.com.key;
    ssl_protocols         TLSv1.2 TLSv1.3;
    ssl_ecdh_curve        X25519:P-256:P-384:P-521;
    server_name           your.example.com;
    index index.html index.htm;
    root  /etc/nginx/html;
    error_page 400 = /400.html;

    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security "max-age=63072000" always;
    # disable nginx version info
    server_tokens off;
    # disable response resource type guessing
    add_header X-Content-Type-Options nosniff;

    location /
    {
        proxy_read_timeout    90;
        proxy_connect_timeout 90;
        proxy_redirect        off;
        proxy_pass http://wordpress:80;
        proxy_set_header      X-Real-IP remote_addr;
        proxy_set_header      X-Forwarded-Forproxy_add_x_forwarded_for;
        proxy_set_header      Host blog.qiuzhizhe.top;
        proxy_set_header X-Forwarded-Proto scheme;
        client_max_body_size 10m;
    }

    # 记得加上这个,后续自动续签验证需要的
    location /.well-known/ {
        root /etc/nginx/html;
        index index.html index.htm;
    }


}

server {
    listen 80;
    listen [::]:80;
    server_name your.example.com;

    location /.well-known/acme-challenge {
        root /etc/nginx/html;
    }

    location / {
        return 301 https://http_host$request_uri;
    }
}

保存成your.example.com.conf然后覆盖掉原来的即可,然后重启nginx容器
至此,完成

此作者没有提供个人介绍
最后更新于 2025-01-17