nginx(docker) 如何更新 letsencrypt 证书
发表于更新于
字数总计:1.2k阅读时长:5分钟 华夏
nginx(docker) 如何更新 letsencrypt 证书
HumphreyDan当前的个人主页是运行在 docker nginx 上的。为了安全起见,把所有的 http 请求已经转发到了 https, 免费的 SSL 证书过期了,所以使用了 letsencrypt 的免费证书来签名。但是它默认的是 3 个月有效期,所以必须得定期去更新。否则就会导致 nginx 服务不可用了。以下为如何在 docker 上更新 letsencrypt 证书.
部署架构
众所周知,docker 的命令配置大都很长,一般是通过shell 脚本或者 docker-compose.yaml 文件来进行管理的。而我采用的就是后者。
如果一台主机上运行了多个 docker 容器,那么这个 docker-compose.yaml 就可能会很大。每次调用 docker-compose up/down 时都会导致所有的容器被销毁重建。所以这里采用了 sidecar 的模式,既可以保证各个容器的配置文件各自保存,又能保证容器之间可以互相访问。
以下以 nginx 和 couchdb 为例.
couchdb/docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| version: "3.6"
services: couchdb: image: couchdb container_name: couchdb volumes: - "./config/local.ini:/opt/couchdb/etc/local.ini" - "./data:/opt/couchdb/data" restart: always ports: - '5984:5984' networks: - default - main networks: main: external: true
|
这里新建了一个名为 main 的 networks, 属性 external
设置为 true, 同时设置容器的 networks 为 default + main, 后面只要其他容器都在 main 这个网络内,都是可以直接 localhost 或者端口互相访问的。
nginx/docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| version: "3.6"
services: nginx: container_name: "home" restart: always image: nginx ports: - "80:80" - "443:443" volumes: - ./nginx/html:/usr/share/nginx/html:rw - ./nginx/etc/nginx:/etc/nginx:rw - ./certbot/letsencrypt/live:/etc/letsencrypt/live:rw - ./certbot/letsencrypt/archive:/etc/letsencrypt/archive:rw - ./certbot/dhparam-2048.pem:/etc/letsencrypt/dhparam-2048.pem:rw networks: - default - main external_links: - obsidian_couchdb environment: - TZ=Asia/Shanghai networks: main: external: true
|
那么在 nginx 中就可以直接访问 couchdb 了.
1 2 3 4
| location /couchdb { rewrite /couchdb(.*) $1 break; proxy_pass http://couchdb:5984; }
|
使用 letsencrypt 生成证书
首先看下 letsencrypt 的 docker-compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| version: "3.6"
services: certbot: image: certbot/certbot:latest container_name: home_certbot volumes: - ./letsencrypt:/etc/letsencrypt:rw - ./log:/var/log:rw command: certonly -n --webroot -w=/etc/letsencrypt --email dang8080@qq.com -d dang8080.cn --agree-tos --force-renewal
|
letsencrypt 提供了 certbot 命令行工具来生成 SSL 证书. 这里同样使用 docker-compose.
certbot 运行时,需要本机提供一个 http 服务,即外部能访问的 http://[本机域名]/.well-known/acme-challenge/[随机字符串] http 服务。本机域名就是要申请 SSL 证书的域名。
这里的 http 服务有两个选择:
1、如果已经有了 nginx/apache 等服务,那么使用它就行,不过需要配置路由和文件映射(因为是运行在 docker 中)
2、使用 certbot 提供的 http 服务
这里我选择了方案1, nginx 需要添加一条新 location 满足 letsencrypt 访问的需求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| server { listen 80; listen [::]:80; server_name dang8080.cn localhost; root /usr/shar/nginx/html;
location / { root /usr/share/nginx/html; return 301 https://dang8080.cn$request_uri; }
location ^~ /.well-known/acme-challenge/ { allow all; default_type "text/plain"; root /var/www/dang8080.cn; } }
|
注意: /.well-known/acme-challenge 的 root 必须是 /var/www/dang8080.cn 否则会报 404.
certbot 使用的参数
–webroot -w 指定生成的 ssl 证书目录,注意这里是在 docker 中运行的,所以需要将其映射到本地文件系统
–agree-tos 跳过 cli 中的交互式问询
–force-renewal 如果指定目录有证书还没过期,那么也要强制重新更新
–standalone 就是 certbot 开启一个新的 http 服务.
执行完后就能在本地看到生成的 ssl 证书了
配置 nginx
因为 nginx 运行在 docker 中,而生成的 ssl 证书在其他目录,所以需要将 ssl 证书目录也映射到 ngixn 容器中.
1 2 3
| - ./certbot/letsencrypt/live:/etc/letsencrypt/live:rw - ./certbot/letsencrypt/archive:/etc/letsencrypt/archive:rw - ./certbot/dhparam-2048.pem:/etc/letsencrypt/dhparam-2048.pem:rw
|
需要说明的是:letsencrypt 生成的 live 目录证书会软链接到 archive 目录,而 docker 对软链接支持不友好,所以需要同时映射 archive 目录和 live 目录
同时为了 ssl 安全,使用 2048位的 DH 参数. 生成方式 openssl dhparam -out dhparam-2048.pem 2048
https.conf
1 2 3 4 5
| ssl_certificate /etc/letsencrypt/live/dang8080.cn/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/dang8080.cn/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/dang8080.cn/chain.pem;
ssl_dhparam /etc/letsencrypt/dhparam-2048.pem;
|
定期更新
前面提到,letsencrypt 生成的 ssl 证书一般只有3个月有效期,所以得定期更新.这里使用 crontab 更新就行.
rewnew.sh
1 2 3 4 5 6
| #! /usr/bin/env sh
pushd ~/[]/certbot && sudo docker-compose up -d && sudo docker kill --signal=HUP [] && sudo docker-compose down
|
或者
1 2 3 4 5 6 7
| #!/usr/bin/env sh
sudo docker run -it --rm \ -v /home/[]certbot/letsencrypt:/etc/letsencrypt \ -v /home/[]certbot/log:/var/log \ certbot/certbot \ renew --webroot -w /etc/letsencrypt --quiet && sudo docker kill --signal=HUP []
|
编辑 crontab: crontab -e
1
| 0 1 * * 0 ~/homepage/certbot/renew.sh
|