Let's Encrypt通配证书
正如 Let's Encrypt 验证(challenge) 所述,要实现域名证书的通配证书,需要使用 DNS-01 验证 :
DNS-01 验证 的原理就是通过在域名的TXT记录中放置特定值来证明用户控制域名的DNS系统,所以本文的手工配置部分完整体现这个过程。然后在后半段自动脚本配置部分,就是通过Cloudflare提供的DNS API来完成自动化过程。
准备工作
安装certbot:( NGINX反向代理https )
apt-get update
apt-get install software-properties-common
add-apt-repository ppa:certbot/certbot
apt-get update
apt-get install python3-certbot-nginx
Certbot
dnf install epel-release
dnf install certbot python3-certbot-nginx
# 如果是Apache,则使用
# dnf install certbot python3-certbot-apache
手工配置
DNS-01 验证 要求在DNS服务器上提供一个特定的TXT记录 _acme-challenge.<YOUR_DOMAIN>
。举例,我的域名是 cloud-atlas.dev
,则我需要生成一个 _acme-challenge.cloud-atlas.dev
记录:
cloud-atlas.dev
域名的 acme challenge DNS记录TXTcertbot certonly -d *.cloud-atlas.dev -d cloud-atlas.dev \
--preferred-challenges dns-01 --manual -m admin@cloud-atlas.dev
备注
certbot
支持多个域名签发同一个证书,我这里使用了域名通配符 *.cloud-atlas.dev
以及一个根域名 cloud-atlas.dev
。我验证过了 *.cloud-atlas.dev
不能代表 cloud-atlas.dev
,所以至少需要2个配置项,否则实际访问时 docs.cloud-atlas.dev
和 www.cloud-atlas.dev
正常,而 cloud-atlas.dev
则会报告证书不正确
此时输出内容类似:
cloud-atlas.dev
域名的 acme challenge DNS记录TXTSaving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.cloud-atlas.dev
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:
_acme-challenge.cloud-atlas.dev.
with the following value:
QE7TvP8sgOgfOzHYcTeePwf5IrobSO04Lb22rHh_cmU
Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.cloud-atlas.dev.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Successfully received certificate.
Certificate is saved at: /usr/local/etc/letsencrypt/live/cloud-atlas.dev/fullchain.pem
Key is saved at: /usr/local/etc/letsencrypt/live/cloud-atlas.dev/privkey.pem
This certificate expires on 2025-11-24.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
注意,其中在 certbot
输出了 DNS TXT record
之后,需要将这个记录添加到Cloudflare的DNS记录中,然后按照提示访问 https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.cloud-atlas.dev. 查看记录是否生效。
也可以手工执行命令 dig _acme-challenge.cloud-atlas.dev. TXT
查看添加的DNS TXT记录是否已经生效。
当记录生效以后,再按下回车键,让certbot完成证书生成。按照提示,这个证书有3个月有效期
NGINX配置
我在 Nginx配置文件的include 方法拆解修订了 NGINX反向代理https 配置,已经运行成功。这次在 在FreeBSD Jail中运行Nginx 重新部署,借用和整理上述 Nginx配置文件的include 配置:
tree
输出配置文件列表.
├── conf.d
│ └── cloud-atlas.dev.conf
├── includes
│ ├── proxy
│ │ └── proxy_set.conf
│ ├── server_name.conf
│ └── ssl
│ └── ssl_set.conf
options-ssl-nginx.conf
和 ssl-dhparams.pem
在上述结合 Let's encrypt cert配置中 ssl_set.conf
中,有两个特殊文件:
options-ssl-nginx.conf
这个配置文件是certbot
基于 https://ssl-config.mozilla.org/ 工具创建的SSL配置文件,我从之前certbot
中复制过来。实际上这个配置文件也可以直接使用 moz://a SSL Configuration Generator 来创建
/usr/local/etc/letsencrypt/options-ssl-nginx.conf
# Intermediate: General-purpose servers with a variety of clients, recommended for almost all systems
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# see also ssl_session_ticket_key alternative to stateful session cache
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl-dhparams.pem
是一个包含Diffie-Hellman擦书的文件,这些参数对于SSL/TLS连接中启用完美前向保密(Perfect Forward Secrecy, PFS)至关重要,尤其在使用Diffie-Hellman密钥交换密码时。虽然Let's Encrypt本身提供了SSL/TLS证书,但是它并不直接生成或管理ssl-dhparams.pem
文件。这个文件是一个独立组件,可以增强SSL/TLS配置的安全性,尤其与 Nginx 或 Apache 等WEB服务器一起使用
执行以下敏玲可以生成 4096-bit Diffie-Hellman参数并保存为 dhparam.pem
(注意,这个4096-bit Diffie-Hellman参数提供了强级别安全,但是会花费很长时间生成):
openssl
生成 dhparam.pem
openssl dhparam -out /usr/local/etc/letsencrypt/dhparam.pem 4096
另一个生成方法是参考 moz://a SSL Configuration Generator 配置说明中方法(我没有使用)
dhparam.pem
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
curl https://ssl-config.mozilla.org/ffdhe2048.txt > /usr/local/etc/letsencrypt/dhparam.pem
自动配置
备注
由于无法解决阿里云强制"网站备案"对HTTPS TLS握手的 SNI(Server Name Indication) 嗅探和TCP reset,我目前放弃了自建 NGINX反向代理https ,改为采用 Cloudflare Tunnel 来实现内部服务器对外输出服务。所以,暂时不再搞Let's encrypt证书,这段 acme.sh
脚本自动申请和更新证书的实践我没有做。
看以后需要再搞,这里仅记录备查。
GitHub: acmesh-official/acme.sh 提供了一个完全采用shell编写的ACME客户端协议实现,非常方便用于申请证书和保持证书更新:
完全采用shell编写的ACME协议客户端
完整支持了ACME协议实现
支持ECDSA certs
支持SAN和wildcard certs
只使用一个脚本来自动完成 issue, renew 和 install 证书
不需要root/sudoers权限
支持Docker运行
支持IPv6
通过cron实现更新或错误通知
待实践...
参考
Generate A Let’s Encrypt certificate using Certbot and DNS Validation 手工执行
certbot
命令生成DNS TEXT record
添加到Cloudflare DNS记录中,然后手工执行certbot
DNS-01 验证 完成部署,可以帮助我们理解整个过程Generating options-ssl-nginx.conf and ssl-dhparams in certonly mode 手工配置时
certbot
只生成了证书,还需要补充生成options-ssl-nginx.conf
和ssl-dhparams.pem
How to issue Let’s Encrypt wildcard certificate with acme.sh and Cloudflare DNS 通过辅助脚本
acme.sh
实现Cloudflare DNS API操作来自动完成证书生成和更新,实际使用较为方便How to issue a Let’s Encrypt Wildcard SSL certificate with Acme.sh
Automating Let’s Encrypt Lifecycle with Posh-Acme and Cloudflare