我有一个使用 Docker 容器运行的现有服务:
- nginx(
nginx:1.13.5
) - node-api(节点容器)
- node-website(节点容器)
我想为 api 和网站添加 SSL 证书。所以我使用certbot/certbot
docker 容器来执行此操作,没有任何问题。
我已经使用挑战生成了证书dns
,并运行以下命令(从我的本地机器):
docker run --rm -it \
--name certbot \
-v $(pwd)/letsencrypt:/etc/letsencrypt \
certbot/certbot \
certonly --manual -d api.mydomain.com --preferred-challenges dns --renew-by-default --email xxx@xxxx --agree-tos --manual-public-ip-logging-ok
我被要求输入 TXT DNS 记录,_acme-challenge.api.mydomain.com
我按照要求输入了,然后顺利生成了证书。
然后我更新了我的 Nginx 配置(/etc/nginx/nginx.conf/api.conf
):
upstream api {
server node-api:5000 max_fails=3;
}
map $http_upgrade $connection_upgrade {
default "upgrade";
"" "";
}
# Force HTTPS
server {
listen 80;
server_name api.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name api.domain.com;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_certificate /etc/nginx/certificates/api.domain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certificates/api.domain.com/privkey.pem;
ssl_trusted_certificate /etc/nginx/certificates/api.domain.com/chain.pem;
access_log /var/log/nginx/api-domain.access.log main;
error_log /var/log/nginx/api-domain.error.log error;
location / {
proxy_pass http://api;
proxy_redirect off;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
一切顺利,重启了我的服务器,现在可以完美运行 letsencrypt 证书!太棒了!
问题
现在开始测试更新证书...麻烦来了。首先,我只是尝试运行命令,renew --dry-run
但没有成功。
尝试从 /etc/letsencrypt/renewal/api.mydomain.com.conf 更新证书 (api.mydomain.com) 时出现意外错误:手动插件不起作用;您现有的配置可能存在问题。错误为:PluginError('当以非交互方式使用手动插件时,必须使用 --manual-auth-hook 提供身份验证脚本。',)。跳过。
因此我尝试使用独立选项:
docker run --rm -it \
--name certbot \
-v $(pwd)/letsencrypt:/etc/letsencrypt \
certbot/certbot \
renew --dry-run --standalone --preferred-challenges dns
并收到此错误:
尝试从 /etc/letsencrypt/renewal/api.mydomain.com.conf 更新证书 (api.mydomain.com) 时出现意外错误:所选插件不支持任何首选挑战。跳过。
所以我推断我不能使用dns
挑战来更新证书,这很公平。
让我们尝试一下tls-sni
Nginx 是否支持(我已验证,它已启用)
docker run --rm -it \
--name certbot \
-v $(pwd)/letsencrypt:/etc/letsencrypt \
certbot/certbot \
renew --dry-run --standalone --preferred-challenges tls-sni
现在我遇到了这个错误:
尝试从 /etc/letsencrypt/renewal/api.mydomain.com.conf 更新证书 (api.mydomain.com) 时出现意外错误:授权程序失败。api.mydomain.com (tls-sni-01):urn:acme:error:unauthorized :: 客户端缺乏足够的授权 :: tls-sni-01 质询的验证证书不正确。从 13.210.106.2:443 请求 e0fd03ddade6d902d5947028985253ba.63b177f317335bf9297f0bb963135fee.acme.invalid。收到 2 个证书,第一个证书名为“api.mydomain.com”。跳过。
我想知道是否需要在 Nginx 端启用某些特定功能,例如OCSP
,ssl_stapling
或者ssl_dhparam
我还注意到,如果我尝试在与获取证书的服务器不同的服务器上重新运行 certonly,则dns
挑战值是不一样的。
所以我有两个问题:
我可以
tls-sni
通过调整 nginx 配置轻松解决验证挑战吗?如果我在实际服务器(运行 nginx 容器的地方)上重新运行
certonly
challengedns
,则使用新生成的记录更新 TXT 记录。我可以稍后使用certonly
命令更新证书吗?TXT 记录值会随时间而变化吗?
提前致谢
答案1
ServerFault 上没有太多活动,因此答案如下:
https://github.com/certbot/certbot/issues/5252#issuecomment-346500852
答案2
谢谢 maxwell2022!根据您的回答,我的最终解决方案如下。在 CentOS 7 上测试。我手动创建了目录 /etc/letsencrypt/acme-challenge。
NGINX 服务器块
server {
listen 80;
server_name MY_DOMAIN;
location /.well-known/acme-challenge/ {
root /etc/letsencrypt/acme-challenge;
}
}
创建证书
docker run -it --rm --name certbot -v /etc/letsencrypt:/etc/letsencrypt -v /var/lib/letsencrypt:/var/lib/letsencrypt certbot/certbot certonly --webroot -w /etc/letsencrypt/acme-challenge/ --domain MY_DOMAIN --agree-tos --email MY_EMAIL
更新证书
docker run -it --rm --name certbot -v /etc/letsencrypt:/etc/letsencrypt -v /var/lib/letsencrypt:/var/lib/letsencrypt certbot/certbot renew --webroot -w /etc/letsencrypt/acme-challenge/
docker kill --signal=HUP proxy
答案3
当问题首次出现时,这不是您的问题,但现在它会导致问题,所以我会提一下:
TLS-SNI 挑战正在逐步淘汰因为它们在许多常见托管平台下都不安全。如果您目前依赖以这种方式颁发的证书,则需要过渡到基于 HTTP 或 DNS 的挑战。