通过 acme.sh 脚本申请免费的 SSL 证书

一、简要概述

acme.sh 是一个免费、开源、自动化的 ACME 客户端工具,可用于申请免费的 SSL 证书。它可以帮助网站管理员轻松地实现 HTTPS 等功能,提高网站的安全性和可靠性。

ACME 协议的说明:该协议定义了客户端(通常是证书申请者或服务器管理员)和证书颁发机构之间的交互过程。ACME 客户端使用 ACME 协议与证书颁发机构的 ACME 服务端进行通信,实现自动申请证书、证明域名所有权、获取证书、以及在证书到期前续订证书等功能。

提示:acme.sh 和 Certbot 都是 ACME 客户端工具,虽然它们和 ACME 服务端的交互逻辑都是相似的,但它们由不同团队维护,所以使用上会有很多不同的地方(例如:不同的命令参数、不同的证书生成路径、不同的插件支持等)。

相比 Certbot 而言,acme.sh 具有如下优势:

  • acme.sh 更加轻量和易于安装(acme.sh 是 Shell 脚本程序,默认就能在各种 Linux 系统上运行,且没有其他依赖关系,而 Certbot 是 Python 脚本程序,依赖 Python 环境);
  • acme.sh 支持更多的 CA(Certbot 默认只支持 Let’s Encrypt,但 acme.sh 可同时支持 Let’s Encrypt、ZeroSSL、Buypass、Google、SSL.com 等 CA 机构,参考:https://github.com/acmesh-official/acme.sh/wiki/CA)
  • acme.sh 官方文档对于中文支持更友好;
  • acme.sh 对于 DNS API 的支持更完善(如:阿里云、腾讯云、华为云等,具体 DNS API 支持参考:https://github.com/acmesh-official/acme.sh/wiki/dnsapi),而 Certbot 默认对阿里云、腾讯云、华为云等不支持。

二、安装

1
2
3
4
5
6
7
8
9
10
11
#acme.sh依赖一些工具包(如果系统没有则需要安装相关依赖包)
#socat工具包:acme.sh用其实现自动启动临时的Web服务进行HTTP验证(仅 --standalone)
#cron工具包:acme.sh用其实现自动化续期证书(可通过命令:crontab -l 检查是否安装有cron服务)
apt install -y socat cron
#yum install -y socat cronie

#安装acme.sh
#普通用户和 root 用户都可以安装使用,默认安装到~/.acme.sh/目录里
#为了方便使用,安装后,安装脚本会自定在~/.bashrc里通过alias设置环境变量,只需要执行source ~/.bashrc命令或者重新打开终端即可使用
curl https://get.acme.sh | sh
source ~/.bashrc

三、卸载

1
2
acme.sh --uninstall	#自动删除alias环境变量等
rm -rf ~/.acme.sh

四、更新

1
2
3
4
5
6
7
#手动更新
acme.sh --upgrade

#开启自动升级(如需)
acme.sh --upgrade --auto-upgrade
#关闭自动更新
acme.sh --upgrade --auto-upgrade 0

五、使用

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
##修改默认CA(可选)
#acme.sh之前使用Let’s Encrypt作为默认CA,但v3.0版本后使用ZeroSSL作为默认CA
#CA可选配置值:letsencrypt、zerossl、buypass、google、ssl.com(简单来说,如果没有特殊需求,免费使用建议选择letsencrypt和zerossl,如果愿意付费则可选择buypass、ssl.com)
#如果默认CA无法颁发,可选修改 CA
acme.sh --set-default-ca --server <CA>
#示例:
acme.sh --set-default-ca --server letsencrypt


##注册账号(需改成自己的邮箱)
#--email EMAIL(简写:-m EMAIL):账号邮箱地址。可用于自动注册 ACME 账号,还可用于证书到期前 20 天、10 天和 1 天时接收到到期通知邮件(对于letsencrypt)。如:--email [email protected]
acme.sh --register-account -m [email protected]


##方式1:自动HTTP验证方式申请证书
#使用条件:(1)需要公网 IP;(2)开启 HTTP 验证端口(默认 80,可通过 --httpport 选项自定义监听端口,但仍然会通过 80 端口进行验证,当使用 --httpport 时,需要反向代理 80 端口到自定义端口,参考:https://github.com/acmesh-official/acme.sh/issues/1230#issuecomment-362177631)
#需要本地运行一个监听80端口的web服务用来给acme服务器验证域名所有权(如果没有启动web服务监听该端口,则acme.sh会自动临时启动一个监听80端口的web服务,用来完成验证)
#ACME 客户端会在Web服务器的根目录(以下-w指定的目录路径)下自动创建一个特定的临时文件(即:.well-known/acme-challenge/<random_token>),然后CA的ACME服务端会通过HTTP协议请求访问此文件(其中访问的url地址为:http://example.com/.well-known/acme-challenge/<random_token>),访问到该文件则说明用户对域名具有控制权,通过用户的控制权情况间接确定用户是否是域名的拥有者(即所有权)。
#-d(--domain):指定域名,如:-d example.com,支持指定多个域名,如:-d example.com -d www.example.com
#-w(--webroot):指定Web服务的根目录路径(需要根据Web服务的相关配置来设置,如:-w /opt/nginx/html)
#--apache 或 --nginx:如果本地运行有apache或nginx等已运行80端口的服务器,可加参数:--apache 或 --nginx,以从其相关配置文件中自动获取80端口的网站根目录,而不需要指定网站根目录。提示:指定--apache 或 --nginx要求nginx或apache是通过标准化安装的(即软件包的安装路径和配置文件路径要和在线包管理器安装方式的路径相同)
#--standalone:如果本地没有运行任何Web服务, 80端口是空闲的, 那么可以指定--standalone以临时运行一个webserver, 临时听在80端口, 完成验证:
#-k(--keylength):指定申请的证书类型(ECC证书或者RSA证书),可选值:ECC证书:ec-256(默认)、ec-384、ec-521;RSA证书:2048、3072、4096。示例:申请ECC证书:--keylength ec-256,申请RSA证书:--keylength 2048(提示:ECC证书通常比RSA证书更推荐,因为它提供了更高的安全性和更小的密钥长度)

#申请证书前需要开放防火墙的 tcp 80 端口,如下:
#(1)对于 UFW 防火墙
ufw allow 80/tcp
#(2)对于 FirewallD 防火墙:
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload

#使用示例:
#通过 --standalone 自动开启一个 80 端口用于 HTTP 验证并自动生成证书(要求 80 端口不能被占用)
acme.sh --issue \
-d example.com \
-d www.example.com \
--standalone

#使用系统中的任意 HTTP 服务自动生成证书(通过 -w 指定访问 HTTP 服务 80 端口时的 Web 根目录路径)
acme.sh --issue \
-d example.com \
-d www.example.com \
-w /opt/nginx/html

#通过 --nginx 指定根据系统中的 nginx 配置自动生成证书
#提示:指定--nginx要求nginx是通过标准化安装的(即软件包的安装路径和配置文件路径要和在线包管理器安装方式的路径相同)
acme.sh --issue \
-d example.com \
-d www.example.com \
--nginx


##方式2:手动DNS验证方式申请证书
#使用条件:需要手动在域名托管服务商的面板上解析给定的txt记录用来验证域名所有权
#优势:不需要公网 IP,不需要开放 HTTP 验证端口
acme.sh --issue \
--dns \
-d example.com \
-d www.example.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
#执行以上命令后acme.sh会生成相应的txt记录显示出来, 只需要手动在域名托管商的管理面板中添加这条txt记录即可
# 解析示例如下:
# _acme-challenge.example.com -> cVe1Jgrp2BE3zLcLrDuJpckdAV9fHhJbe7XpO7rhiXo
# _acme-challenge.www.example.com(注意对于层级较多的域名一定要填写正确)-> rPe1Jgrp2BE3zLcLrDuJpckdAV9fHhJbe7XpO7rhi
# 可执行如下命令来验证txt记录是否解析成功
# dig TXT _acme-challenge.example.com
# dig TXT _acme-challenge.www.example.com
#等待解析完成之后, 最后只需要指定选项:--renew 再执行如下命令即重新生成证书即可:
acme.sh --renew \
-d example.com \
-d www.example.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please


##方式3:自动dns验证方式申请证书
#需要使用到DNS API,并需要配置域名解析商的 API 认证信息
#当 acme.sh --issue --dns <dns-name> 生成证书时,会自动更新一些配置文件
#(1)设置的 API 认证信息会被自动记录在/root/.acme.sh/account.conf配置文件中, 后续再使用该 DNS 插件时, 就不需要指定了,当然,如果重新指定,那么会覆盖account.conf配置文件中原来的配置
#(2)设置的 DNS 插件类型会记录在~/.acme.sh/example.com/example.com.conf配置文件中,如果重新指定,那么会覆盖account.conf配置文件中原来的配置
#不同的域名解析商的DNS API使用方式相似,但有些许区别,可参考:https://github.com/acmesh-official/acme.sh/wiki/dnsapi

#以DNSPod DNS为例,操作如下:
#先访问 https://console.dnspod.cn/account/token/token 创建“DNSPod Token”(注意不是“腾讯云 API 密钥”),然后进行如下设置:
#设置 DNS 插件的 API 认证信息
export DP_Id="xxxxx"
export DP_Key="xxxxx"
#通过指定DNS API类型自动进行dns验证并申请证书
acme.sh --issue --dns dns_dp -d example.com -d *.example.com

#以Cloudflare DNS为例,操作如下:
#使用参考:https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
#先访问:https://dash.cloudflare.com/profile/api-tokens 创建获得 “API Tokens” 或者查看使用 “Global API Key”(选其一即可),推荐使用 API Tokens,因为其权限相对较小,更安全,注意:API Tokens 创建后只能查看一次,如果忘记了只能重新创建

#设置 DNS 插件的 API 认证信息
#使用 API Tokens 时(可选)
export CF_Token="xxxxx"
#使用 Global API Key 时(可选)
export CF_Key="xxxxx"
export CF_Email="[email protected]"
##通过指定DNS API类型自动进行dns验证并申请证书
acme.sh --issue --dns dns_cf -d example.com -d *.example.com


##安装证书
#注意:默认生成的证书都会放在 ~/.acme.sh/example.com 目录里,请不要直接使用此目录下的文件,因为这里面的文件都是 acme.sh 内部使用的,该目录结构可能会发生变化,故建议把证书安装复制到真正需要用它的地方。安装命令将一些重要的命令参数(如:证书、私钥等文件的安装路径、reloadcmd 等 hook 命令脚本等,其中 hook 命令会经 base64 编码)记录在 ~/.acme.sh/example.com/example.com.conf 配置文件中,当证书更新(如续期更新证书)时,将会重新安装复制最新证书到配置文件所指定的路径中,并执行 reloadcmd 等 hook 命令脚本(如:重载 nginx 配置文件等)。
#安装证书后,就可以到 web 服务器(如:Nginx)配置使用证书了
#提示:
#(1)重复执行时,如果路径或 hook 等内容有变化会自动修改 example.com.conf 配置文件;
#(2)执行该命令候会立即执行 --reloadcmd 对应的 hook 命令
#(3)对于多域名证书,安装时只要指定用于命名证书的域名即可(默认为申请证书时的第一个指定域名),不需要指定全部域名
acme.sh --install-cert \
-d example.com \
--key-file /path/example.com-key.pem \
--fullchain-file /path/example.com-fullchain.pem \
--reloadcmd "nginx -s reload"


##查看已申请的证书
#列出已申请的所有证书
acme.sh --list
#查看已申请的指定证书配置信息
acme.sh --info -d example.com


##吊销指定证书
acme.sh --revoke -d example.com
##从证书生成目录中删除指定证书
acme.sh --remove -d example.com #逻辑删除,只是改文件后缀,实际并不会删除掉文件
rm -rf ~/.acme.sh/example.com #实际删除(提示:如果为ECC证书,则目录为:example.com_ecc)


##续期证书
#申请证书后acme.sh会自动将续期任务添加到系统的用户定时任务中。(目前默认每60天会自动更新,今后有可能会缩短这个时间)
#列出系统的定时任务(可查看acme.sh自动添加的定时任务)
crontab -l

#续期指定证书(如需手动需求)
#默认证书未到期,不会成功续期(即重新颁发新的证书),但可指定 --force 来强制重新颁发证书,但不建议,因为申请颁发太多次会触发申请次数限制
acme.sh --renew -d example.com
#acme.sh --renew --force -d example.com #强制重新颁发证书
#续期所有证书(如需手动需求)
acme.sh --renew-all



##修改已生证书的 DNS 插件(设之前使用 DNSPod,现在改为 Cloudflare)
#(1)编辑账号配置文件(~/.acme.sh/account.conf),添加或修改相应 DNS 插件的 API 认证信息(如果没有则需要添加,如果之前已经配置存在可以自行选择是否需要修改,其中认证变量名前需要加 “SAVED_” 前缀),如下:
SAVED_CF_Key='xxxxx'
SAVED_CF_Email='[email protected]'

#(2)编辑指定证书的配置文件(~/.acme.sh/example.com/example.com.conf),可修改 Le_Webroot(DNS 插件名称)。也可根据自己调整情况选择修改 Le_RealKeyPath(证书秘钥文件安装路径)、Le_RealFullChainPath(证书链文件安装路径,其中证书链文件含证书)、Le_ReloadCmd(证书安装完成后重新加载执行的 hook 命令,Le_ReloadCmd 的值的格式为 __ACME_BASE64__START_<经 Base64 编码的命令>__ACME_BASE64__END_),如下:
Le_Webroot='dns_cf'
Le_RealKeyPath='/opt/ssl-certs/acme.sh-qcmoke.link-key.pem'
Le_ReloadCmd='__ACME_BASE64__START_L29wdC9uZ2lueC9zYmluL25naW54IC1zIHJlbG9hZA==__ACME_BASE64__END_'
Le_RealFullChainPath='/opt/ssl-certs/acme.sh-qcmoke.link-fullchain.pem'

#(3)如果不放心修改正不正确,可以强制重新生成证书(可选,没必要,因为申请颁发太多次会触发申请次数限制),如下:
acme.sh --renew --force -d example.com

#(4)或者强制重新重头申请生成证书(可选,没必要,因为申请颁发太多次会触发申请次数限制),如下:
#设置 DNS 插件的 API 认证信息(以 Global API Key 为例)
export CF_Key="xxxxx"
export CF_Email="[email protected]"
#重新生成证书(会同步更新example.com.conf配置文件)
#提示:acme.sh --renew 只能使用之前存储的配置信息来重新生成证书,但不能指定参数来修改 DNS 插件类型、DNS 插件对应 API 认证信息、证书、密钥安装路径等的配置内容。所以需要指定 --issue --force 来重新生成证书并重修改配置文件(其中指定 --force 表示强制重新颁发证书)
acme.sh --issue --force --dns dns_cf -d example.com -d *.example.com
#重新安装证书
acme.sh --install-cert \
-d example.com \
--key-file /path/example.com-key.pem \
--fullchain-file /path/example.com-fullchain.pem \
--reloadcmd "nginx -s reload"

申请证书后,会将证书保存的目录为:~/.acme.sh/example.com(提示:如果为 ECC 证书,则目录为:example.com_ecc),包含一下文件:

  • ca.cer:CA 证书文件
  • fullchain.cer:证书链文件(中间证书)
  • example.com.cer:证书文件
  • example.com.key:私钥文件
  • example.com.conf:指定证书的配置文件
  • example.com.csr:证书请求文件
  • example.com.csr.confacme.sh 对于特定证书请求文件的配置文件

关于 Let’s Encrypt 证书申请次数限制:

  • 生产环境限制

    • 每个域名/证书每周最多只能签发 5 次

    • 每个 IP 地址每小时最多能提交 300 个证书申请请求

  • 测试环境限制(指定 --staging--test 选项时)

    • 测试环境下颁发的证书无法被浏览器或操作系统信任
    • 测试环境下每个域名/证书每周最多可签发 50 次
    • 测试环境下每个 IP 地址每小时最多能提交 300 个请求
    • 测试环境下没有通过 HSTS 预载的域名(生产环境支持通过 HSTS 预载的域名)

六、备份还原

备份(在原服务器上进行)

1
2
3
4
5
6
7
8
##备份acme.sh的脚本、证书、配置文件
cd /root/
#打包备份目录
tar -zcvf acme.sh.tgz .acme.sh/

# 使用 sz 下载备份包并删除备份包(可选)
# sz -y acme.sh.tgz
# rm -f acme.sh.tgz .acme.sh/acme.sh.cron.tmp

还原(在新服务器上进行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#使用 rz 上传备份包到 /root 目录(可选)
# rz -y

##还原 acme.sh 的脚本、证书、配置文件
cd /root/
#删除目录(如有)
# rm -rf .acme.sh/
#解包还原目录
tar xf acme.sh.tgz
#删除备份包(可选)
# rm -f acme.sh.tgz

#还原 acme.sh 的定时任务
#删除 acme.sh 有关的定时任务(如有)
# acme.sh --uninstall-cronjob
#安装 acme.sh 有关的定时任务
acme.sh --install-cronjob

#还可通过 crontab -e 命令来手动编辑来追加定时任务
#或者(RedHat 系列系统):echo '35 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null' >> /var/spool/cron/root
#或者(Debian 系列系统):echo '35 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null' >> /var/spool/cron/crontabs/root
#或者:(crontab -l ; echo '35 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null') | crontab -

参考:https://www.cnblogs.com/tssc/p/17428657.html

七、参考



----------- 本文结束 -----------




如果你觉得我的文章对你有帮助,你可以打赏我哦~
0%