轶哥

📚 Having fun with AI Agent. Always learning.

    Docker搭配免费SSL证书
    •   更新:2021-08-25 14:04:29
    •   首发:2020-03-07 23:39:33
    •   教程
    •   6279

    MySQL定时备份程序中我有提到一个基于Docker快速生成SSL证书的方式。该文章整理了该方案的详细教程。

    基于Let's Encrypt免费SSL证书。

    官方介绍

    docker-letsencrypt-nginx-proxy-companion

    官方示例

    使用方法

    非docker-compose模式下。

    第一步:执行下述两条命令

    docker run --detach \
        --name nginx-proxy \
        --publish 80:80 \
        --publish 443:443 \
        -e ENABLE_IPV6=true \
        --volume /etc/nginx/certs \
        --volume /etc/nginx/vhost.d \
        --volume /usr/share/nginx/html \
        --volume /var/run/docker.sock:/tmp/docker.sock:ro \
        jwilder/nginx-proxy
    
    docker run --detach \
        --name nginx-proxy-acme \
        --volumes-from nginx-proxy \
        --volume /var/run/docker.sock:/var/run/docker.sock:ro \
        --volume acme:/etc/acme.sh \
        --env "DEFAULT_EMAIL=mail@yourdomain.tld" \
        nginxproxy/acme-companion
    

    第二步:启动项目时加上相关环境变量

    以Nginx静态资源站点为例:

    docker run -itd --restart always \
          -v 你的静态资源文件:/usr/share/nginx/html \
        --env "VIRTUAL_PORT=80" \
        --env "VIRTUAL_HOST=你的域名" \
        --env "LETSENCRYPT_HOST=你的域名" \
        nginx
    

    此时,直接访问LETSENCRYPT_HOST中的域名,显示证书正常即可(可能有一分钟左右延迟)。

    第三步:重复第二步

    是不是很简单,几乎零配置,连修改nginx配置的工夫都省了。

    环境变量说明

    VIRTUAL_PORT:您的项目监听的端口。这里有个坑,某些情况下监听端口不一定成功。建议每次暴露内部端口,例如增加-p 80参数,确保监听一定成功。详见Node.js示例。

    VIRTUAL_HOST:站点域名,可多个,以英文逗号分割。

    LETSENCRYPT_HOST:申请SSL证书的域名,可多个,以英文逗号分割。

    LETSENCRYPT_EMAIL:通知邮箱,选填。(很多情况下填了也没用)

    docker-compose示例参考:https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion/blob/master/docs/Docker-Compose.md

    更多示例用法

    Node.js 项目

    docker run -itd --name appointment-service --restart always \
        -m 1024m \
        --link mysql:mysql \
        -p 80 \
        --env "VIRTUAL_PORT=80" \
        --env "VIRTUAL_HOST=appointment.api.ykfz.pw" \
        --env "LETSENCRYPT_HOST=appointment.api.ykfz.pw" \
        -v /etc/localtime:/etc/localtime:ro \
        -v /root/site/appointment-service:/root \
        -w /root \
        --restart=always node:13.7.0 npm start
    

    说明:-p 80参数将明确暴露容器内80端口,随机转发到宿主机某一端口。缺少该参数将可能导致监听失败出现502报错

    泛解析用法

    由于申请免费通配符证书需要ACMEv2支持,以上方法暂不适用于通配符域名(原因 2021年08月25日14:03:29更新:nginxproxy/acme-companion 或已经支持泛域名。

    解决思路:

    1. 参考另外一篇博文配置自动续期的免费通配符SSL证书
    2. 未测试的方案:https://github.com/adferrand/docker-letsencrypt-dns
    3. 推荐搭配acme.sh实现该需求。

    思路3具体操作如下:

    1. 按照acme.sh说明安装acme.sh。通常只需要执行curl https://get.acme.sh | sh命令。
    2. 根据https://github.com/acmesh-official/acme.sh/wiki/dnsapi 寻找你的域名DNS提供商,参照说明配置API账号。例如腾讯云则参考DNSPod配置方式,阿里云则参考第十一条Aliyun的配置方式。如果您使用的DNS解析提供商不在该列表,可以在github搜搜看。
    3. 生成SSL证书。例如acme.sh --issue --dns dns_dp -d *.app.ykfz.pw

    将得到:

    [2020年 03月 07日 星期六 21:40:19 CST] Your cert is in  /root/.acme.sh/*.app.ykfz.pw/*.app.ykfz.pw.cer
    [2020年 03月 07日 星期六 21:40:19 CST] Your cert key is in  /root/.acme.sh/*.app.ykfz.pw/*.app.ykfz.pw.key
    [2020年 03月 07日 星期六 21:40:19 CST] The intermediate CA cert is in  /root/.acme.sh/*.app.ykfz.pw/ca.cer
    [2020年 03月 07日 星期六 21:40:19 CST] And the full chain certs is there:  /root/.acme.sh/*.app.ykfz.pw/fullchain.cer
    
    1. 下载此代码https://gist.github.com/yi-ge/6c13dfddabd128a630bea9481ac8fb98nginx.tmpl文件或参考jtegtmeier提供的配置方法:https://github.com/nginx-proxy/nginx-proxy/commit/07655df85884b4ee7937a422ccd33b413b584a02

    感谢jtegtmeier提供的方案!

    1. 以类似下述命令的方式启动nginx-proxy
    docker run --detach \
        --name nginx-proxy \
        --publish 80:80 \
        --publish 443:443 \
        --volume /etc/nginx/certs \
        --volume /etc/nginx/vhost.d \
        --volume /usr/share/nginx/html \
        --volume /var/run/docker.sock:/tmp/docker.sock:ro \
        -v `pwd`/nginx.tmpl:/app/nginx.tmpl \
        -v /root/.acme.sh:/root/.acme.sh \
        jwilder/nginx-proxy
    

    增加了acme路径映射,请确保nginx.tmpl在执行文件的目录下。

    1. 增加环境变量配置并启动容器。
    docker run -itd -m 1024m \
      --restart=always \
      --name appointment-ui \
      -v /root/site/appointment-ui:/usr/share/nginx/html \
      --env "VIRTUAL_HOST=*.app.ykfz.pw" \
      --env "CERT_PATHNAME=/root/.acme.sh/*.app.ykfz.pw/*.app.ykfz.pw.cer" \
      --env "PRIVATE_KEY_PATHNAME=/root/.acme.sh/*.app.ykfz.pw/*.app.ykfz.pw.key" \
      --env "CHAIN_PATHNAME=/root/.acme.sh/*.app.ykfz.pw/fullchain.cer" \
      nginx 
    

    请参考第二步得到的证书,对应设置证书路径。

    Custom pathnames are set on the virtual hosts using these environment variables:

    • CERT_PATHNAME=/path/to/cert
    • PRIVATE_KEY_PATHNAME=/path/to/key
    • CHAIN_PATHNAME=/path/to/chain

    注意,此处有个坑。请检查crontab配置,在自动更新SSL证书的配置下方增加nginx重启指令。

    例如:

    49 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
    55 0 * * * /usr/bin/docker restart nginx-proxy
    

    如果未使用nginx-proxy(即使用的是本地nginx),则参考添加如下命令:

    17 0 1 * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
    22 0 1 * * /use/sbin/nginx -s reload
    

    配置完毕。

    总结: 免费泛解析SSL证书必须修改DNS进行验证,每个季度一次。无论是手工修改DNS还是通过DNS API,都请做一个TODO List,在3个月后检查一下自己的网站是否正常运行。

    打赏
    交流区

    暂无内容

    尚未登陆
    发布
      上一篇 (Office(Word Excel PPT)转PDF-开放API)
    下一篇 (Windows应用以管理员权限开机自启(开源))  

    评论回复提醒