Nginx自动证书Cerbot
Certbot 是一个开源的命令行工具,用于自动化获取和续期 Let's Encrypt 颁发的 SSL/TLS 证书。Let's Encrypt 是一个免费的、自动化的、开放的证书颁发机构(CA),它提供免费的 SSL/TLS 证书,用于加密网站流量。
每天运行一次 Certbot 就能实现自动续期30天内过期的证书。
基本概念
通配符证书
通配符证书(wildcard certificate)是可以与多个子域名一起使用的公钥证书。与传统证书相比,通配符证书可以比每个子域的证书更便宜、更方便。
证书是针对域名颁发的,与具体的主机无关,已经申请的证书可以迁移到任何主机。因此颁发证书只需验证你对域名的所有权。
ACME
自动证书管理环境(Automatic Certificate Management Environment, ACME)是一种通信协议,用于自动化证书颁发机构与其用户的 Web 服务器之间的交互,允许以非常低的成本自动部署公钥基础设施。
ACME使用“客户端/服务器”架构,使用HTTPS传输数据。想要通过ACME协议申请证书,证书颁发机构必须支持ACME,实现ACME服务器,而我们需要一个ACME客户端。
ACME客户端
https://letsencrypt.org/zh-cn/docs/client-options/
Let's Encrypt
Let's Encrypt是由Internet Security Research Group(ISRG)运营的非营利性证书颁发机构,它免费为传输层安全(TLS)加密提供X.509证书。它是世界上最大的证书颁发机构,被超过 2.65 亿个网站使用,目标是所有网站都使用HTTPS。
Let's Encrypt支持ACME协议,并支持通配符证书。
Certbot
Certbot is EFF's tool to obtain certs from Let's Encrypt and (optionally) auto-enable HTTPS on your server.
It can also act as a client for any other CA that uses the ACME protocol.
https://github.com/certbot/certbot
Certbot是一个ACME客户端,也是ACME客户端的参考实现,使用Python编写。Certbot默认使用Let's Encrypt作为证书颁发机构。
验证方式
上文说到,证书颁发机构需要验证你对域名的所有权,然后才能给你证书。
虽然ACME客户端可能有五花八门的验证选项,但是归结起来只有两种类型:HTTP质询和DNS质询
HTTP质询
这是当今最常见的验证方式。与ACME服务器沟通后,ACME客户端将一个特定的文件放在主机Web服务器的一个特定路径上。ACME服务器会通过申请的域名与此路径访问这个文件,如果一切正确,则验证完毕。HTTP质询只能使用80端口。
可以看出,HTTP质询需要你事先添加DNS记录,使你申请证书的域名指向运行ACME客户端的主机,并且该主机必须是可公网访问的。其次,需要一个已经在运行的Web服务器,ACME客户端需要足够的权限在Web服务器下放置文件。
HTTP质询不支持通配符证书。
DNS质询
DNS质询与Web服务器无关,而是通过检查DNS记录来验证对域名的所有权。ACME服务器只需要检查域名下特定的TXT记录即可完成验证。
为了让ACME客户端自动添加TXT记录,DNS托管商必须提供编辑DNS记录的API,并且由DNS托管商提供身份认证的方案。此外,ACME客户端还要有支持这些API的插件。
DNS质询看起来麻烦,但更具普适性,而且功能强大。DNS质询不依赖于具体主机,并且支持通配符证书。
Certbot 的基本使用
docker pull certbot/certbot
docker run -it --rm certbot/certbot -h
验证方式
- 通过
HTTP
请求验证,会向http://你的域名/.well-known/acme-challenge/
发送一条请求。 - 通过
DNS
解析,需要在域名解析中增加一条_acme-challenge.你的域名
的TXT记录用于验证。
命令
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:
obtain, install, and renew certificates:
(default) run Obtain & install a certificate in your current webserver
certonly Obtain or renew a certificate, but do not install it
renew Renew all previously obtained certificates that are near
expiry
enhance Add security enhancements to your existing configuration
-d DOMAINS Comma-separated list of domains to obtain a certificate for
(the certbot apache plugin is not installed)
--standalone Run a standalone webserver for authentication
(the certbot nginx plugin is not installed)
--webroot Place files in a server's webroot folder for authentication
--manual Obtain certificates interactively, or using shell script
hooks
-n Run non-interactively
--test-cert Obtain a test certificate from a staging server
--dry-run Test "renew" or "certonly" without saving any certificates
to disk
manage certificates:
certificates Display information about certificates you have from Certbot
revoke Revoke a certificate (supply --cert-name or --cert-path)
delete Delete a certificate (supply --cert-name)
reconfigure Update a certificate's configuration (supply --cert-name)
manage your account:
register Create an ACME account
unregister Deactivate an ACME account
update_account Update an ACME account
show_account Display account details
--agree-tos Agree to the ACME server's Subscriber Agreement
-m EMAIL Email address for important account notifications
More detailed help:
-h, --help [TOPIC] print this message, or detailed help on a topic;
the available TOPICS are:
all, automation, commands, paths, security, testing, or any of the
subcommands or plugins (certonly, renew, install, register, nginx,
apache, standalone, webroot, etc.)
-h all print a detailed help page including all topics
--version print the version number
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_注意_:==修改其中的任何文件 /etc/letsencrypt
可能会损坏它们==,因此 Certbot 无法再正确管理其证书,我们不建议这样做..
certbot
的命令有很多种不同的参数,这些参数也主要是为了自动生成http验证文件或自动添加dns解析等功能,主要的大体说下:
--manual
sudo certbot certonly --manual \
--preferred-challenges=http \
-d example.com \
-d www.example.com
certonly
: 只获取证书,不自动配置 Web 服务器。--manual
: 启用手动模式。--preferred-challenges=http
: 使用 HTTP 验证方式(默认是 DNS 验证)。- 选择使用 DNS 验证(
--preferred-challenges=dns
),你需要手动在 DNS 记录中添加 TXT 记录。 -d example.com -d www.example.com
: 指定你要获取证书的域名。
运行完成后需要在 http://example.com/.well-known/acme-challenge/
路径下创建一个文件,文件内容为 Certbot 提供的字符串。
创建文件后,Certbot 会自动尝试访问该 URL 进行验证。如果验证成功,Certbot 会生成 SSL 证书,并将其存储在 /etc/letsencrypt/live/example.com/
目录下
然后再配置 Nginx
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 其他配置...
}
自动续期
certbot renew
--nginx
和 --apache
apt-get install certbot python3-certbot-nginx
运行之前你需要创建一个基本的 Nginx 配置
server {
listen 80;
listen [::]:80;
server_name example.com;
return 404;
}
获取并自动配置 Nginx
certbot --nginx -d example.com -d www.example.com
Apache
apt-get install certbot python3-certbot-apache
certbot --apache -d example.com -d www.example.com
--dns-xxx
apt-get install certbot python3-certbot-dns-cloudflare
apt-get install certbot python3-certbot-dns-google
apt-get install certbot python3-certbot-dns-route53
创建令牌
# cloudflare.ini
dns_cloudflare_api_token = your-cloudflare-api-token
chmod 600 cloudflare.ini
Cloudflare
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /path/to/cloudflare.ini \
-d example.com
-d www.example.com
其他服务商类似
--standalone
再80端口创建一个Web服务用于验证。
certbot certonly --standalone -d example.com -d www.example.com
--webroot
--webroot
是一种使用 Certbot 获取 SSL 证书的方式,它通过在现有的 Web 服务器(如 Nginx 或 Apache)的 Web 根目录下创建一个临时文件来验证域名所有权。这种方式不需要停止现有的 Web
服务器,也不会占用 80 或 443 端口。
certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com
certonly
: 只获取证书,不自动配置 Web 服务器。--webroot
: 使用 Webroot 模式,Certbot 会在指定的 Web 根目录下创建临时文件。-w /var/www/html
: 指定 Web 根目录的路径。-d example.com -d www.example.com
: 指定你要获取证书的域名。
通过webroot
的方式运行后,会在两个地方产生文件:- 一个是在命令行配置的
--webroot-path
指定目录下产生临时文件,用于http验证。 - 一个是验证成功会产生存放证书的文件,默认是在
/etc/letsencrypt/live/你的域名
目录下,需要注意的是这些证书是个软链接,对应着../archive
下,所以我们在做volume
映射时不要只映射到live
这个目录,而是要映射/etc/letsencrypt
这个目录,否则无法找到相关的证书文件。
限制
Certbot
申请证书是有次数限制的,重复申请5次以上,再次请求会报too many certificates already issued...
等错误,会停用一周后才能再继续,此时只能再换个域名或者是等一周了,参考速率限制。
Certbot 不会自动添加到定时任务 cron
, 所以需要定时运行。
简单使用
certbot certonly --webroot --webroot-path path/to/webroot --domain subdomain.example.com
# 自动配置 web 服务
certbot --nginx --domain subdomain.example.com
certbot --apache --domain subdomain.example.com
# 续期
certbot renew
# --dry-run 模拟结果
certbot --webroot --webroot-path path/to/webroot --domain subdomain.example.com --dry-run
# 获取测试证书
certbot --webroot --webroot-path path/to/webroot --domain subdomain.example.com --test-cert
Docker
使用主机自带的 Corn 定时重启 Certbot
Compose
services:
nginx:
image: nginx:1.15-alpine
restart: unless-stopped
container_name: nginx
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
ports:
- "80:80"
- "443:443"
certbot:
image: certbot/certbot
container_name: ssl
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
# 启动
docker compose up nginx -d
docker compose exec -it ssl -d example.com
使用主机自带的corn运行容器
# 每天2点运行 证书更新 和 重启 Nginx
0 2 * * * docker exec -it ssl renew --quiet
30 2 * * * docker exec -it nginx nginx -s reload
Compose 配置复杂度蛮高的。
构建容器
在 Nginx 中按照 Certbot 并配置定时任务
FROM nginx:stable-alpine
RUN apk add --no-cache certbot certbot-nginx && \
echo "0 2 * * * /usr/bin/certbot renew --quiet" | tee -a /etc/crontabs/root && \
echo "30 2 * * * /usr/sbin/nginx -s reload" | tee -a /etc/crontabs/root
EXPOSE 80
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
OR
FROM nginx:stable-alpine
RUN apk add --no-cache certbot certbot-nginx
COPY crontab /var/spool/cron/crontabs/root
EXPOSE 80
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]
Crontab 定时执行
# 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
# 当天晚上2点执行一次
0 2 * * * /usr/bin/certbot renew >> /var/log/renew.log 2>&1 && /usr/sbin/nginx -s reload >> /var/log/reload.log 2>&1
或者
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/bin/certbot renew --quiet") | crontab -
(crontab -l 2>/dev/null; echo "0 3 * * * /usr/sbin/nginx -s reload") | crontab -
资料参考
Letsencrypt 官网
https://letsencrypt.org/zh-cn/
使用Certbot与Cloudflare插件申请通配符证书
https://juejin.cn/post/7069995574266691614
Certbot使用DNS和文件验证两种方式申请SSL证书
https://blog.ansheng.me/post/certbot-uses-dns-and-file-verification-to-apply-for-ssl-certificates.html
Letsencrypt通过DNS的TXT记录来验证域名有效性
https://opstrip.com/2018/12/28/Getting-Letsencrypt-Certificate-with-DNS-TXT/
Docker环境下自动更新Let’s Encrypt SSL证书
https://www.cnblogs.com/gao88/p/10596143.html
docker-nginx/stable/alpine/Dockerfile
https://github.com/nginxinc/docker-nginx/blob/master/stable/alpine/Dockerfile
项目参考
Boilerplate for nginx with Let’s Encrypt on docker-compose
https://github.com/wmnnd/nginx-certbot
Automatically create and renew website certificates for free using the Let's Encrypt certificate authority.
https://github.com/JonasAlfredsson/docker-nginx-certbot
开源的SSL证书管理工具,可以帮助你自动申请、部署SSL证书,并在证书即将过期时自动续期。
https://github.com/usual2970/certimate