使用Certbot申请免费 HTTPS 证书及自动续期
有大佬包装了阿里云插件和cerbot: https://github.com/tengattack/certbot-dns-aliyun
或者单独使用cerbot 和aliyun插件: https://github.com/justjavac/certbot-dns-aliyun
官方文档: https://letsencrypt.org/zh-cn/docs/
单独使用cerbot
如果您使用的是 Certbot,可以通过 --test-cert 或 --dry-run 命令行选项使用我们的测试环境。 如果您使用的是其他 ACME 客户端,请阅读他们有关使用我们的测试环境进行测试的说明。
正式环境中:
每周最多 5 张重复证书 的限制。
每个注册域名可签发的证书数量(每周 50 份)
每个账户三小时内最多可创建 300 份订单。
每份证书的域名数量最多为 100 个
每个 IP 地址每 3 个小时最多可创建 10 个账户。
帐户最多可以有 300 个待验证授权。
测试环境中
使用与生产环境类似的速率限制,但具体数据有所变化:
每个注册域名允许颁发的证书数量限制为每周 30000 张。
重复证书限制为每周 30000 张。
每小时允许 60 次验证失败。
每个 IP 地址注册账户数量限制为每个 IP 每 3 小时允许注册 50 个账户。
对于 ACME v2,新订单限制为每个帐户每 3 小时 1500 个。
验证方式
申请证书后,会进行域名解析验证,目前有dns和http方式. 官方推荐dns方式.
dns验证方式: 需要增加一条域名解析记录
http验证方式: 需要http,80端口可以访问到 .well-known/pki-validation/fileauth.txt
安装 Certbot
https://github.com/certbot/certbot/releases/tag/v2.11.0
yum install epel-release -y
yum install certbot -y常用命令
certbot常用命令:
certbot [子命令] [选项] [-d 域名]
(默认) run:获取并安装证书到当前网页服务器;
certonly:获取或更新证书,但是不安装;
renew :更新已经获取但快过期的所有证书;
-d 域名列表:指定证书对应的域名列表,域名之间使用逗号分隔;
--email zcsupport@163.com 需要提供有效的邮箱
--agree-tos 同意条款
--apache:使用Apache插件进行身份认证和安装
--standalone:运行一个独立的网页服务器用于身份认证
--nginx:用Nginx插件进行身份认证和安装
--webroot:把身份认证文件放置在服务器的网页根目录下;
–manual: 使用交互式或脚本钩子的方式获取证书;
-n:非交互式运行;
--test-cert:从预交付服务器上获取测试证书
–-dry-run:测试获取或更新证书,但是不存储到本地硬盘;
--key-type rsa: 这个参数指定了证书使用的密钥类型。RSA 是一种常用的公钥加密算法。
--此参数表明将生成一个基于 RSA 加密的密钥。你还可以选择使用 ECC(椭圆曲线加密)等其他密钥类型。
--force-renew:强制更新证书
–-disable-hook-validation:更新前检查错误,如有错误将不会执行更新操作
--preferred-challenges dns 使用dns验证方式,需要在域名解析增加记录
--preferred-challenges http-01 使用http验证方式,需要能访问到 .well-known/pki-validation/fileauth.txt证书管理
看证书信息:
certbox certificates #显示使用Certbot生成的所有证书的信息,包括过期时间
certbot-auto --no-self-upgrade --force-renew certificates
#--force-renew 强制更新 --no-self-upgrade 不更新letsencrypt
撤销证书:
certbox revoke
certbox revoke --cert-path /etc/letsencrypt/archive/www.mydomain.com/cert1.pem #输入"y"确定撤销证书
删除证书:
certbot delete #删除证书。回车后会列出所有证书,选择一个想要删除的证书即可
手动续期证书:续期前需要关闭nginx服务
certbot renew --force-renew #强制更新证书
certbot-auto renew --force-renew #强制更新证书
自动续期证书:每月的1号1点执行(certbot证书有效期是三个月)
crontab -e #写到定时任务
0 1 1 * * /usr/bin/certbot renew --force-renew --renew-hook "/usr/local/nginx/sbin/nginx -s reload"
0 1 1 * * /usr/local/bin/certbot-auto renew --no-self-upgrade --force-renew --renew-hook "/usr/local/nginx/sbin/nginx -s reload" 申请证书
域名分为主域名 test.com 和泛域名 *.test.com。
申请时,可以使用命令交互式,非交互式, 或者使用hook钩子
# 泛域名:
certbot certonly -d *.test.com --manual --preferred-challenges dns
# 主域名:
certbot certonly -d test.com --manual --preferred-challenges dns
#dns验证方式
certbot certonly --email zcsupport@163.com --agree-tos -d *.dianyinpay.com --manual --preferred-challenges dns
#http验证方式
certbot certonly --email zcsupport@163.com --webroot -w /opt/offical-web --preferred-challenges http-01 -d *.dianyinpay.com这时会出现下图的界面
[root]& certbot certonly --email zcsupport@163.com --agree-tos -d *.dianyinpay.com --manual --preferred-challenges dns
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Requesting a certificate for *.dianyinpay.com
Performing the following challenges:
dns-01 challenge for dianyinpay.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.dianyinpay.com with the following value:
Lb04xjI3ItnbCE9iNZrB971OPvpRhRekBfqt5Dr9wFs
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
Subscribe to the EFF mailing list (email: zcsupport@163.com).
Starting new HTTPS connection (1): supporters.eff.org
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/dianyinpay.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/dianyinpay.com/privkey.pem
Your certificate will expire on 2024-11-08. To obtain a new or
tweaked version of this certificate in the future, simply run
certbot again. To non-interactively renew *all* of your
certificates, run "certbot renew"
- 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
证书说明:
/etc/letsencrypt/live/test.com/fullchain.pem全证书/etc/letsencrypt/live/test.com/privkey.pem私钥
在阿里控制台域名解析增加验证记录:
使用http验证
#指定webroot, 需要可以访问到一下url,以完成验证
# https://www.example.com/.well-known/pki-validation/fileauth.txt
$ sudo certbot certonly --webroot -w /usr/share/nginx/html/ -d www.domain1.com -d domain1.com
$ sudo certbot certonly --webroot -w /usr/share/nginx/html/ -d www.domain2.com -d domain2.com
certbot certonly --email zcsupport@163.com --webroot -w /opt/offical-web --preferred-challenges http-01 -d *.dianyinpay.com配置nginx
server {
listen 443;
ssl on;
server_name domain1.com www.domain1.com;
ssl_certificate /etc/letsencrypt/live/www.domain1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.domain1.com/privkey.pem;
}删除证书
# 删除已有的证书(可选择)
sudo certbot delete
sudo certbot delete --cert-name example.com定时更新
#核心是使用certbot renew. 但最好在申请时不适用--manual,否则需要提供--manual-auth-hook
# 定时更新证书 (还未验证效果)
sudo crontab -e
# 添加: 30 2 * */2 * /usr/bin/certbot renew >> /var/log/le-renew.log
使用standalone模式
standalone会单独启动一个服务来处理验证请求,也就意味着如果你的主机需要关停80端口(或和443端口)的web服务,譬如正在运行的nginx、Apache需要关停。
standalone模式,其中-d参数指定拟申请ssl证书的域名
可以通过多个-d参数指定多个域名,但你得确保这些指定的多个域名均能正常解析到当前主机
使用阿里云插件
在已经安装cerbot的基础下使用justjavac作者提供的命令:
https://github.com/justjavac/certbot-dns-aliyun
alidns.sh
#!/bin/bash
FLAG="(\.com\.cn|\.gov\.cn|\.net\.cn|\.org\.cn|\.ac\.cn|\.gd\.cn)$"
if ! command -v aliyun >/dev/null; then
echo "错误: 你需要先安装 aliyun 命令行工具 https://help.aliyun.com/document_detail/121541.html。" 1>&2
exit 1
fi
DOMAIN=$(expr match "$CERTBOT_DOMAIN" '.*\.\(.*\..*\)')
SUB_DOMAIN=$(expr match "$CERTBOT_DOMAIN" '\(.*\)\..*\..*')
if echo $CERTBOT_DOMAIN |grep -E -q "$FLAG"; then
DOMAIN=`echo $CERTBOT_DOMAIN |grep -oP '(?<=)[^.]+('$FLAG')'`
SUB_DOMAIN=`echo $CERTBOT_DOMAIN |grep -oP '.*(?=\.[^.]+('$FLAG'))'`
fi
if [ -z $DOMAIN ]; then
DOMAIN=$CERTBOT_DOMAIN
fi
if [ ! -z $SUB_DOMAIN ]; then
SUB_DOMAIN=.$SUB_DOMAIN
fi
if [ $# -eq 0 ]; then
aliyun alidns AddDomainRecord \
--DomainName $DOMAIN \
--RR "_acme-challenge"$SUB_DOMAIN \
--Type "TXT" \
--Value $CERTBOT_VALIDATION
/bin/sleep 20
else
RecordId=$(aliyun alidns DescribeDomainRecords \
--DomainName $DOMAIN \
--RRKeyWord "_acme-challenge"$SUB_DOMAIN \
--Type "TXT" \
--ValueKeyWord $CERTBOT_VALIDATION \
| grep "RecordId" \
| grep -Eo "[0-9]+")
aliyun alidns DeleteDomainRecord \
--RecordId $RecordId
fientrypoint.sh
#!/bin/bash
# Activate the virtual environment
source /opt/venv/bin/activate
# Configure Aliyun CLI
aliyun configure set --profile akProfile --mode AK --region $REGION --access-key-id $ACCESS_KEY_ID --access-key-secret $ACCESS_KEY_SECRET
# Obtain the certificate
certbot certonly -d "$DOMAIN" --manual --preferred-challenges dns --manual-auth-hook "/usr/local/bin/alidns" --manual-cleanup-hook "/usr/local/bin/alidns clean" --agree-tos --email $EMAIL --non-interactive
# Start cron daemon
crond -f -l 2dockerfile
FROM alpine:latest
# Install dependencies
RUN apk --no-cache add wget tar sudo certbot bash python3 py3-pip && \
apk --no-cache add --virtual build-dependencies gcc musl-dev python3-dev libffi-dev openssl-dev make
# Install aliyun-cli
RUN wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz && \
tar xzvf aliyun-cli-linux-latest-amd64.tgz && \
mv aliyun /usr/local/bin && \
rm aliyun-cli-linux-latest-amd64.tgz
# Copy and install certbot-dns-aliyun plugin
RUN wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh && \
mv alidns.sh /usr/local/bin/alidns && \
chmod +x /usr/local/bin/alidns
# Create virtual environment for Python packages
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Install Python dependencies in virtual environment
RUN pip install --upgrade pip && \
pip install aliyun-python-sdk-core aliyun-python-sdk-alidns
# Copy entrypoint script
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Set environment variables (to be provided during runtime)
ENV REGION=""
ENV ACCESS_KEY_ID=""
ENV ACCESS_KEY_SECRET=""
ENV DOMAIN=""
ENV EMAIL=""
ENV CRON_SCHEDULE="0 0 * * *"
# Setup cron job for certbot renew
RUN echo "$CRON_SCHEDULE /opt/venv/bin/certbot renew --manual --preferred-challenges dns --manual-auth-hook '/usr/local/bin/alidns' --manual-cleanup-hook '/usr/local/bin/alidns clean' --agree-tos --email $EMAIL --deploy-hook 'cp -r /etc/letsencrypt/live/$DOMAIN/* /etc/letsencrypt/certs'" > /etc/crontabs/root
# Create directory for certificates
RUN mkdir -p /etc/letsencrypt/certs
# Make sure cron is running
RUN touch /var/log/cron.log
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]安装(CommandLine)
安装 aliyun cli 工具
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
tar xzvf aliyun-cli-linux-latest-amd64.tgz
sudo cp aliyun /usr/local/bin
rm aliyun安装完成后需要配置凭证信息
安装 certbot-dns-aliyun 插件
wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
sudo cp alidns.sh /usr/local/bin
sudo chmod +x /usr/local/bin/alidns.sh
sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
rm alidns.sh申请证书
测试是否能正确申请:
certbot certonly -d *.example.com --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run正式申请时去掉 --dry-run 参数:
certbot certonly -d *.example.com --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"证书续期
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run如果以上命令没有错误,把 --dry-run 参数去掉。
自动续期
添加定时任务 crontab。
crontab -e
输入
1 1 */1 * * root certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --deploy-hook "nginx -s reload"安装(Dockerfile)
下载Dockerfile以及entrypoint.sh,确保他们在同一文件夹下。目前Dockerfile中默认下载amd64版本,其他架构请修改对应的Aliyun CLI URL。
创建Image
进入Dockerfile同目录:
docker build -t certbot-alicli .使用代理(可选):
docker build . \
--build-arg "HTTP_PROXY=http://127.0.0.1:7890" \
--build-arg "HTTPS_PROXY=http://127.0.0.1:7890" \
-t certbot-alicli运行容器
docker run \
-e REGION=YOUR_REGEION \
-e ACCESS_KEY_ID=YOUR_ACCESS_KEY \
-e ACCESS_KEY_SECRET=YOUR_ACCESS_SECRET \
-e DOMAIN=YOUR_DOMAIN \
-e EMAIL=YOUR_NOTIFICATION_EMAIL \ // 证书刷新通知邮箱
-e CRON_SCHEDULE="0 0 * * *"\ // 自定义证书刷新间隔
-v /path/to/your_certs:/etc/letsencrypt/certs \
-d certbot-alicli本次只安装aliyun插件,不安装dockerfile相关
在阿里云创建访问账户
增加资源权限
会提示有AccessKey Id,AccessKey Secret.
在服务器创建aliyun配置
#交互式
aliyun configure --mode <AuthenticateMode> --profile <profileName>
--mode:指定凭证类型,默认为AK类型。
--profile:指定配置名称。若不指定,则使用默认身份凭证配置调用命令。如果指定的配置已存在,则修改已存在配置;若不存在,则创建新配置。
#非交互式
aliyun configure set [--settingName <settingValue>]... --mode <AuthenticateMode> --profile <profileName>
常见的通用选项如下,其适用于任一凭证类型。
--profile(必选):指定配置名称。如果指定的配置存在,则修改配置。若不存在,则创建配置。
--region(必选):指定默认地域。详情请参见地域和可用区。
--language:指定阿里云CLI显示的语言,默认为英语。
--mode:指定配置的凭证类型,默认为AK类型。更多关于支持类型的详细信息,请参见身份凭证类型。
#举例
aliyun configure set \
--profile AkProfile \
--mode AK \
--access-key-id **** \
--access-key-secret **** \
--region **** AK类型凭证为默认凭证类型,使用AccessKey信息作为身份凭证。配置AK类型凭证时可以忽略
--mode选项。
配置必填项如下:AccessKey Id:指定您的AccessKey ID。获取方式请参见创建RAM用户的AccessKey。AccessKey Secret:指定您的AccessKey Secret。获取方式请参见创建RAM用户的AccessKey。Region Id:指定默认区域的Region Id。阿里云支持的Region Id,请参见地域和可用区。
[root@dyp-nginx home]# wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
--2024-08-10 10:18:17-- https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
Resolving aliyuncli.alicdn.com (aliyuncli.alicdn.com)... 111.225.211.240, 111.225.211.239
Connecting to aliyuncli.alicdn.com (aliyuncli.alicdn.com)|111.225.211.240|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14182938 (14M) [application/x-compressed-tar]
Saving to: ‘aliyun-cli-linux-latest-amd64.tgz’
100%[=======================================================================================================================================================================================================>] 14,182,938 35.6MB/s in 0.4s
2024-08-10 10:18:17 (35.6 MB/s) - ‘aliyun-cli-linux-latest-amd64.tgz’ saved [14182938/14182938]
[root@dyp-nginx home]# tar xzvf aliyun-cli-linux-latest-amd64.tgz
aliyun
[root@dyp-nginx home]# sudo cp aliyun /usr/local/bin
[root@dyp-nginx home]# rm aliyun
rm: remove regular file ‘aliyun’? y
[root@dyp-nginx home]# wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
--2024-08-10 10:19:10-- https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
Resolving cdn.jsdelivr.net (cdn.jsdelivr.net)... 46.82.174.69, 2a04:4e42:8c::485
Connecting to cdn.jsdelivr.net (cdn.jsdelivr.net)|46.82.174.69|:443...
#访问不到, 直接自己在服务器粘贴进去. 看alidns.sh文件
[root@dyp-nginx home]# vim alidns.sh
[root@dyp-nginx home]# ls
alidns.sh aliyun-cli-linux-latest-amd64.tgz
[root@dyp-nginx home]# sudo cp alidns.sh /usr/local/bin
[root@dyp-nginx home]# sudo chmod +x /usr/local/bin/alidns.sh
[root@dyp-nginx home]# sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
[root@dyp-nginx home]# aliyun configure --mode AK
Configuring profile 'default' in 'AK' authenticate mode...
Access Key Id []: LTAI5tXXXXXXXXXXXXXXX
Access Key Secret []: sXXXXXXXXXXXXXXXXXXX
Default Region Id []: cn-beijing-l
Default Output Format [json]: json (Only support json)
Default Language [zh|en] en: zh
Saving profile[default] ...Done.
Configure Done!!!
..............888888888888888888888 ........=8888888888888888888D=..............
...........88888888888888888888888 ..........D8888888888888888888888I...........
.........,8888888888888ZI: ...........................=Z88D8888888888D..........
.........+88888888 ..........................................88888888D..........
.........+88888888 .......Welcome to use Alibaba Cloud.......O8888888D..........
.........+88888888 ............. ************* ..............O8888888D..........
.........+88888888 .... Command Line Interface(Reloaded) ....O8888888D..........
.........+88888888...........................................88888888D..........
..........D888888888888DO+. ..........................?ND888888888888D..........
...........O8888888888888888888888...........D8888888888888888888888=...........
............ .:D8888888888888888888.........78888888888888888888O ..............
#测试申请证书
[root@dyp-nginx home]# certbot certonly -d *.dianyinpay.com --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Cert not due for renewal, but simulating renewal for dry run
Simulating renewal of an existing certificate for *.dianyinpay.com
Performing the following challenges:
dns-01 challenge for dianyinpay.com
Running manual-auth-hook command: alidns
Output from manual-auth-hook command alidns:
{
"RecordId": "911049162397126656",
"RequestId": "9517B5B7-62CB-50F9-ACE8-B927E690AFD7"
}
Waiting for verification...
Cleaning up challenges
Running manual-cleanup-hook command: alidns clean
Output from manual-cleanup-hook command alidns:
{
"RecordId": "911049162397126656",
"RequestId": "79B53800-0F28-58DB-AB3D-625120083E90"
}
RegionId 区域编码需要在阿里云上查看:
中国地区