acme.sh 教程

I. 部署 ACME

ACME 是自动证书管理环境(Automatic Certificate Management Environment)的缩写,为证书颁发机构(如 ZeroSSL)和网络服务器之间的自动交互提供了一种易于使用的方法。

1.1 切换 root 用户

📢 注意:
为了解决 --reloadcmd 参数执行命令无权限问题,建议在 root 用户下安装 acme.sh

1.2 安装 acme.sh

参考文档: How to install

  1. 下载安装脚本:
1
curl https://get.acme.sh | sh

输出日志:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Installing from online archive.
Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz
Extracting master.tar.gz
It is recommended to install socat first.
We use socat for standalone server if you use standalone mode.
If you don't use standalone mode, just ignore this warning.
Installing to /root/.acme.sh
Installed to /root/.acme.sh/acme.sh
Installing alias to '/root/.bashrc'
OK, Close and reopen your terminal to start using acme.sh
Installing alias to '/root/.cshrc'
Installing alias to '/root/.tcshrc'
Installing cron job
no crontab for root
no crontab for root
Good, bash is found, so change the shebang to use bash as preferred.
OK
Install success!

📢 国内服务器安装:

1
2
3
4
wget https://github.com/acmesh-official/acme.sh/archive/master.tar.gz
tar -zxvf master.tar.gz
cd cd acme.sh-master
./acme.sh --install

ℹ️ 普通用户和 root 用户都可以安装使用,安装脚本其实是进行了如下操作:

  1. 会把 acme.sh 安装到你所执行命令用户的用户目录下:~/.acme.sh/

  2. 会创建 bashalias,方便你的使用:alias acme.sh=~/.acme.sh/acme.sh

  3. 会自动为你创建 cronjob 脚本,每天零点自动检测所有的证书,如果某证书快过期需要更新,则会自动更新该证书。

安装过程不会污染已有的系统任何功能和文件, 所有的修改都限制在安装目录中: ~/.acme.sh/

  1. 使命令生效
1
source ~/.bashrc
  1. 查看版本
1
acme.sh -v
  1. 开启 acme.sh 自动升级
1
acme.sh --upgrade --auto-upgrade

关闭自动更新

1
acme.sh --upgrade --auto-upgrade  0

II. 设置默认 CA

参考文档: Change default CA to ZeroSSL
从 2021 年 8 月 1 日起,acme.sh 将发布 v3.0,其中默认 CA 将使用 ZeroSSL。
如果您不想每次颁发证书时都指定 --server zerossl ,可以设默认 CA。
比较已知 CA 支持的功能: CA

2.1 ZeroSSL.com CA(默认)

参考文档1: ZeroSSL.com CA
参考文档2: ZeroSSL vs Let’s Encrypt
注意:自 v3 版起,acme.sh 使用 Zerossl 作为默认的证书颁发机构(CA)。在签发新证书前,需要注册账户(一次性)。

1
acme.sh --set-default-ca  --server zerossl

查看更多: https://github.com/acmesh-official/acme.sh/wiki/Server

2.1.1 使用 EAB 证书(推荐)

通过使用 ZeroSSL 的 ACME 功能,您可以免费生成无限量的 90 天 SSL 证书,还支持多域证书和通配符。 您创建的每个证书都将存储在您的 ZeroSSL 账户中。
如果你注册了一个 ZeroSSL 帐户 ,可以使用外部帐户绑定 (EAB) 凭据启动 acme.sh,就像这样:

  1. 生成您的 EAB 证书 https://app.zerossl.com/developer
  2. 注册您的 EAB 证书:
1
2
3
acme.sh --register-account \
--eab-kid xxxxxxxxxxxx  \
--eab-hmac-key xxxxxxxxx

拥有 ZeroSSL 账户的用户可通过 开发人员控制台 管理已签发的证书。

2.1.2 使用电子邮件地址

有免费额度限制(3个单域名证书,查看 ZeroSSL 定价计划

1
acme.sh --register-account -m myemail@example.com 

2.2 Letsencrypt.org CA

1
acme.sh --set-default-ca --server letsencrypt

查看更多: https://github.com/acmesh-official/acme.sh/wiki/Server

III. 签发证书

acme.sh 实现了 acme 协议支持的所有验证协议。 一般有两种方式验证: http 和 dns 验证。

3.1 Webroot 模式

http 方式需要在你的网站根目录下放置一个文件,来验证你的域名所有权,完成验证. 然后就可以生成证书了。

1
acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/ --keylength ec-256

也可以这样(多域名 ECC 证书)

1
acme.sh --issue -w /home/wwwroot/mydomain.com/ -d mydomain.com,www.mydomain.com --keylength ec-256

只需要指定域名,并指定域名所在的网站根目录, acme.sh 会全自动的生成验证文件,并放到网站的根目录,然后自动完成验证,最后会聪明的删除验证文件,整个过程没有任何副作用。

3.2 Apache 模式

如果你用的 apache 服务器, acme.sh 还可以智能的从 apache 的配置中自动完成验证,你不需要指定网站根目录:

1
acme.sh --issue -d mydomain.com --apache --keylength ec-256

3.3 Nginx 模式

如果你用的 nginx 服务器,或者反代,acme.sh 还可以智能的从 nginx 的配置中自动完成验证,你不需要指定网站根目录:

1
acme.sh --issue -d mydomain.com --nginx --keylength ec-256

多域名 ECC 证书:

1
acme.sh --issue -d mydomain.com,www.mydomain.com --nginx --keylength ec-256

📢 注意:
无论是 apache 还是 nginx 模式, acme.sh 在完成验证之后,会恢复到之前的状态,都不会私自更改你本身的配置。好处是你不用担心配置被搞坏,也有一个缺点,你需要自己配置 ssl 的配置,否则只能成功生成证书,你的网站还是无法访问 https。但是为了安全, 你还是自己手动改配置吧。

有时无法自动找到 nginx 配置文件,可以指定一个:

1
acme.sh  --issue  -d example.com  --nginx /etc/nginx/nginx.conf --keylength ec-256

您还可以指定网站 conf

1
acme.sh  --issue  -d example.com  --nginx /etc/nginx/conf.d/example-com.conf --keylength ec-256

3.4 Standalone 模式

如果使用单机模式,请先安装 socat。acme.sh 依赖 socat 用于单机模式。 socat 是一款 Linux 下的工具软件,可以在两个不同的数据流之间建立连接,实现数据传输、转换和处理等功能。

  • 适用 Debian 及其衍生产品:
1
sudo apt install socat
  • 适用 Red Hat 及其衍生产品:
1
sudo yum install socat

3.4.1 独立服务器

要求您是 root/sudoer,或有权限监听 80 端口(TCP)。
如果你还没有运行任何 web 服务, 80 端口是空闲的, 那么 acme.sh 还能假装自己是一个 webserver,临时监听在 80 端口,完成验证:

1
acme.sh --issue -d example.com --standalone --keylength ec-256

3.4.2 独立 SSL 服务器

要求您是 root/sudoer,或拥有监听 443 端口(TCP)的权限。
端口 443(TCP)必须是空闲的监听端口,否则系统会提示您释放该端口并重试。

1
acme.sh --issue --alpn -d example.com --keylength ec-256

3.5 自动集成 DNS API

参考文档: How to use DNS API

3.5.1 CloudFlare

Cloudflare Domain API 提供两种自动签发证书的方法:
(a) 创建具有特定权限的限制性 API 令牌(推荐);
(b) 使用与 Cloudflare 账户关联的全局 API 密钥,该密钥具有所有权限。


(a) 使用限制性应用程序接口令牌
您需要创建一个 API 令牌,该令牌可以是
(i) 具有编辑单个特定 DNS 区域的权限;或
(ii) 具有编辑多个 DNS 区域的权限。


**创建一个 API 令牌 ** 打开 Cloudflare 官网,在“个人资料” -> API 令牌 -> 创建令牌 -> 编辑区域 DNS-使用模板:

Pic_2024-08-24_192911.png

继续以显示摘要 -> 创建令牌。
复制此令牌以访问 Cloudflare API。为安全起见,将不再显示此令牌。


(i)单个 DNS 区域(推荐)
该区 ID 可通过 Cloudflare 官网,在网站 -> 打开“站点” -> 在“概述”页面右侧边栏“区域 ID”

1
2
CF_Token="<api_token>"
CF_Zone_ID="<zone_id>"

(ii)多个 DNS 区域
该区 ID 可通过 Cloudflare 官网,在网站 -> 打开“站点” -> 在“概述”页面右侧边栏“账户 ID”

1
2
CF_Token="<api_token>"
CF_Account_ID="<accound_id>"

签发证书时设置和使用的任何环境变量都将保存在 ~/.acme.sh/account.conf 中,以便今后使用 dns_cf 签发新证书或更新现有证书时自动重复使用。


API 配置
将获取到的 AccessKey 和 Secret 配置到 acme.sh.env 文件

1
vim ~/.acme.sh/acme.sh.env

追加以下内容:

1
2
3
4
5
6
7
# 单个 DNS 区域 (2选1)
export CF_Token="<api_token>"
export CF_Zone_ID="<zone_id>"

# 多个 DNS 区域 (2选1)
export CF_Token="<api_token>"
export CF_Account_ID="<accound_id>"

使配置生效

1
source ~/.bashrc

查看配置的变量是否生效:

1
2
echo $CF_Token
echo $CF_Zone_ID

颁发证书

1
2
3
acme.sh --issue --dns dns_cf \
-d example.com -d '*.example.com' \
--keylength ec-256

会输出如下内容:

1
2
3
4
5
...
[Fri Jan 26 01:22:33 AM EST 2024] Your cert is in: /root/.acme.sh/example.com_ecc/example.com.cer
[Fri Jan 26 01:22:33 AM EST 2024] Your cert key is in: /root/.acme.sh/example.com_ecc/example.com.key
[Fri Jan 26 01:22:33 AM EST 2024] The intermediate CA cert is in: /root/.acme.sh/example.com_ecc/ca.cer
[Fri Jan 26 01:22:33 AM EST 2024] And the full chain certs is there: /root/.acme.sh/example.com_ecc/fullchain.cer

3.5.2 阿里云

  1. 登录阿里云后台,在 RAM 访问控制 -> 身份管理 -> 用户 -> 创建用户

Pic_2024-08-24_193011.png

  1. 给刚刚创建的子账号添加权限

Pic_2024-08-24_193211.png

  1. 将获取到的 AccessKey 和 Secret 配置到 acme.sh.env 文件
1
vim ~/.acme.sh/acme.sh.env

追加以下内容:

1
2
export Ali_Key="<key>"
export Ali_Secret="<secret>"
  1. 使配置生效
1
source ~/.bashrc

查看配置的变量是否生效:

1
2
echo $Ali_Key
echo $Ali_Secre
  1. 颁发证书

📢 注意:
国内使用 acme.sh 默认 ZeroSSL.com CA 可能无法正常获取 SSL 证书,可切换至 Letsencrypt.org CA

1
2
3
acme.sh --issue --dns dns_ali \
-d example.com -d *.example.com \
--keylength ec-256

3.5.2 DNSPod.cn

DNSPod.cn 域名 API 选项要求您首先登录您的帐户,以获取 DNSPod API 密钥和 ID。

1
2
export DP_Id="<id>"
export DP_Key="<key>"

颁发证书

1
acme.sh --issue --dns dns_dp -d example.com -d *.example.com --keylength ec-256

DP_IdDP_Key 将保存在 ~/.acme.sh/account.conf 中,并在需要时重复使用。

3.6 DNS 别名模式

📌 说明:

如果您的 DNS 提供商不支持 API 访问,或者您担心向主域提供 DNS API 访问权限会出现安全问题,则可以使用 DNS 别名模式。

例如,您的主域是 example.com ,它没有 API 访问权限,或者您不想向 acme.sh 授予 API 访问权限,因为它很重要。

您还有另一个域: aliasDomainForValidationOnly.com ,它具有受支持的 DNS API。该域不太重要,可能仅用于验证。

3.6.1 设置主域 CNAME

在主域 DNS 解析中,添加一条 CNAME 记录,指向带有 _acme-challenge. 的 DNS 别名主机名:

1
_acme-challenge.example.com   =>   _acme-challenge.aliasDomainForValidationOnly.com

📢 注意:

如果您使用的是 Cloudflare ,请将 Proxy status 设置为 DNS only 。不要将其设置为代理,这行不通!

3.6.2 添加别名域名 API

参考本文 3.5 章节。

3.6.3 颁发证书

1
2
3
4
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--challenge-alias aliasDomainForValidationOnly.com \
--keylength ec-256

📌 说明:

CA 服务器检查原始域 _acme-challenge.example.com 的 txt 记录来验证您的域,但您在步骤 3.6.1 中设置了 CNAME,因此它会转发到别名域 _acme-challenge.aliasDomainForValidationOnly.com 检查。

acme.sh 知道这一点,所以它只是将正确的 txt 记录添加到 _acme-challenge.aliasDomainForValidationOnly.com

所以,完成了。您将获得 example.com 的证书,但不需要放弃域控制。

3.7 更多用法

更多的用法请参考: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert

IV. 证书安装

前面证书生成以后,接下来需要把证书 copy 到真正需要用它的地方。

📢 注意:
默认生成的证书都放在安装目录下 ~/.acme.sh/ 请不要直接使用此目录下的文件,例如:不要直接让 nginx/apache 的配置文件使用这下面的文件,这里面的文件都是内部使用,而且目录结构可能会变化。
正确的使用方法是使用 --install-cert 命令,并指定目标位置, 然后证书文件会被 copy 到相应的位置, 例如:

4.1 Apache

4.1.1 创建证书存放目录

1
mkdir -p /etc/ssl/example-com

4.1.2 安装证书

1
2
3
4
5
6
acme.sh --install-cert -d example.com \
--cert-file      /etc/ssl/example-com/example.com.cer  \
--key-file       /etc/ssl/example-com/example.com.key  \
--fullchain-file /etc/ssl/example-com/fullchain.cer \
--keylength      ecc \
--reloadcmd      "systemctl force-reload apache2"

4.2 Nginx

4.2.1 创建证书存放目录

1
mkdir -p /etc/ssl/example-com

4.2.2 安装证书

1
2
3
4
5
acme.sh --install-cert -d example.com \
--key-file       /etc/ssl/example-com/example.com.key \
--fullchain-file /etc/ssl/example-com/fullchain.cer \
--keylength      ecc \
--reloadcmd      "chown nobody:nobody -R /etc/ssl/example-com && systemctl force-reload nginx"

Nginx 的配置 ssl_certificate 使用 /etc/ssl/nginx/fullchain.cer ,而非 /etc/ssl/nginx/<domain>.cer ,否则 SSL Labs 的测试会报 Chain issues Incomplete 错误。
--install-cert 命令可以携带很多参数, 来指定目标文件. 并且可以指定 reloadcmd, 当证书更新以后, reloadcmd 会被自动调用,让服务器生效。

📢 注意:

  1. reloadcmd 非常重要,证书可以自动更新。但如果没有正确的 reloadcmd ,证书可能无法刷新到服务器(如 nginx 或 apache)上,那么您的网站将无法在 60 天后显示更新的证书。
  2. 如果需要更改 reloadcmd 命令,请使用新的 reloadcmd 再次运行 --install-cert 命令,它将替换之前的命令( 参考 )。

V. 证书信息

查看已安装证书信息:

1
acme.sh --info -d example.com

会输出如下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
DOMAIN_CONF=/root/.acme.sh/example.com/example.com.conf
Le_Domain=example.com
Le_Alt=no
Le_Webroot=dns_ali
Le_PreHook=
Le_PostHook=
Le_RenewHook=
Le_API=https://acme-v02.api.letsencrypt.org/directory
Le_Keylength=
Le_OrderFinalize=https://acme-v02.api.letsencrypt.org/acme/finalize/23xxxx150/781xxxx4310
Le_LinkOrder=https://acme-v02.api.letsencrypt.org/acme/order/233xxx150/781xxxx4310
Le_LinkCert=https://acme-v02.api.letsencrypt.org/acme/cert/04cbd28xxxxxx349ecaea8d07
Le_CertCreateTime=1649358725
Le_CertCreateTimeStr=Thu Apr  7 19:12:05 UTC 2022
Le_NextRenewTimeStr=Mon Jun  6 19:12:05 UTC 2022
Le_NextRenewTime=1654456325
Le_RealCertPath=
Le_RealCACertPath=
Le_RealKeyPath=/etc/acme/example.com/privkey.pem
Le_ReloadCmd=service nginx force-reload
Le_RealFullChainPath=/etc/acme/example.com/chain.pem

VI. 证书更新

目前证书在 60 天以后会自动更新,你无需任何操作。今后有可能会缩短这个时间,不过都是自动的。你不用担心。
请确保 cronjob 正确安装,看起来是类似这样的:

1
crontab  -l

输出如下内容:

1
56 * * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

手动强制更新证书:

1
acme.sh --renew -d example.com --force

或者,对于 ECC 证书:

1
acme.sh --renew -d example.com --force --ecc

VII. 卸载 acme.sh

7.1 吊销证书

参考文档: revokecert

1
acme.sh --revoke -d example.com

7.2 停止证书更新

要停止证书续期,可以执行以下操作,将证书从续期列表中删除:

1
acme.sh --remove -d example.com

证书/密钥文件未从磁盘中删除。您可以自行删除相应目录(例如 ~/.acme.sh/example.com

7.3 卸载 acme.sh

参考文档: Github Issues #2983

1
2
acme.sh --uninstall
rm -rf  ~/.acme.sh/

VIII. 报错解决

如果报错, 请添加 debug log:

1
acme.sh --issue  .....  --debug 

或者:

1
acme.sh --issue  .....  --debug  2

请参考: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

IX. 参考文档

  1. 参考文档1: acme.sh

  2. 参考文档2: acme.sh wiki