acme.sh快速入门申请SSL证书


概述

前情提要:

这会是一篇系列文章,本想先从 SSL 基本概念科普讲起,结果坑越挖越大。为了不鸽太久,就先把最近刚更完的证书相关操作先来逐步填坑,等后续再反补科普向内容(但愿)。

本系列内容大致分为四篇:

背景

早年间,因 certbot-auto 是基于 Python 2 编写的,而 Python 2 即将寿终正寝,将 certbot-auto 迁移至 Python 3 需要大量工作且非常困难,因此团队决定放弃 certbot-auto 的维护。所以笔者在后续改用了 Let’s Encrypt 上首推的 ACME 客户端(Certbot)来实现自助申请、更新 SSL 证书。

ref: 利用certbot工具申请let’s encrypt证书

但因为 Certbot 本身强依赖 Python 3 运行环境,导致并不是所有客户端都能完美适用。而接着这次破站证书即将到期,重新看了一下目前的 ACME 客户端,从中找到了一款同样是针对 ACME 协议编写的工具 – acme.sh。

acme.sh 是什么

acme.sh 是一个基于 Shell 脚本的开源工具,用于自动化管理和获取 SSL/TLS 证书。它提供了一种简单而灵活的方法来与 Let’s Encrypt 进行交互,并支持其他证书颁发机构(CA)。

使用对比

Certbot 和 acme.sh 都是用于自动化管理和获取 SSL/TLS 证书的工具,但它们在实现方式和功能上有一些区别。下面是它们之间的两个主要对比:

实现语言和依赖关系:

  • Certbot 是使用 Python 编写的,因此在使用之前需要确保系统上已经安装了 Python 解释器和相关依赖库。这意味着您需要处理 Python 环境的配置和维护。
  • acme.sh 是一个基于 Shell 脚本的工具,它在各种 Linux 系统上运行,并且没有其他依赖关系。由于使用 Shell 脚本,它通常更加轻量级和易于安装和使用。

接口和功能:

  • Certbot 提供了一个命令行接口和一个简单的交互式界面,使得使用和管理证书变得更加方便。它有更多的配置选项和功能,例如支持多种 Web 服务器软件和自动配置文件更新。
  • acme.sh 同样提供了命令行接口,并且通过简单的命令和选项可以执行证书管理任务。虽然它的功能相对较少,但是它具有可扩展性和自定义性,通过插件机制可以添加更多功能,例如 DNS 验证插件。

以下,将围绕 acme.sh 来做主要的功能介绍,让你对该工具有个初步认识。


快速入门

环境准备

在开始之前需要升级系统的 CA 证书,以避免后续在申请 SSL 证书时遇到问题。

CentOS

yum install -y ca-certificates

Debian

apt update ; apt install -y ca-certificates

安装 acme.sh

快速安装

curl https://get.acme.sh | sh -s email=nestealin@gmail.com

安装程序将执行以下 3 个操作:

  1. 创建并复制 acme.sh 到你的主目录($HOME):~/.acme.sh/。所有的证书也将放置在这个文件夹中。
  2. 创建别名,例如:设置 alias acme.sh=~/.acme.sh/acme.sh
  3. 创建每日定时任务来检查并更新证书(如果需要)。

注: acme.sh 工具的安装与执行操作均不需要 root 权限,允许在其他系统用户下直接安装与执行。

手动安装

虽然普通用户和 root 用户都可以安装使用,但在本例中将以 root 用户进行安装。

使用如下命令自动安装:

export ACME_HOME="/usr/local/acme.sh"
mkdir -p $ACME_HOME/data
cd /usrCertbotithubusercontent.com/acmesh-official/acme.sh/master/acme.sh
chmod +x acme.sh && ./acme.sh --install-online \
--home $ACME_HOME \
--cert-home $ACME_HOME/data \
--accountemail "nestealin@gmail.com" \
--nocron
ls ./acme.sh && rm -f ./acme.sh && cd $ACME_HOME && ls -l

安装过程输出:

[Sat Aug 17 00:39:43 CST 2024] It is recommended to install socat first.
[Sat Aug 17 00:39:43 CST 2024] We use socat for the standalone server, which is used for standalone mode.
[Sat Aug 17 00:39:43 CST 2024] If you don't want to use standalone mode, you may ignore this warning.
[Sat Aug 17 00:39:43 CST 2024] Installing to /usr/local/acme.sh
[Sat Aug 17 00:39:43 CST 2024] Installed to /usr/local/acme.sh/acme.sh
[Sat Aug 17 00:39:43 CST 2024] Installing alias to '/root/.bashrc'
[Sat Aug 17 00:39:43 CST 2024] Close and reopen your terminal to start using acme.sh
[Sat Aug 17 00:39:43 CST 2024] Installing alias to '/root/.cshrc'
[Sat Aug 17 00:39:43 CST 2024] Installing alias to '/root/.tcshrc'
[Sat Aug 17 00:39:43 CST 2024] bash has been found. Changing the shebang to use bash as preferred.
[Sat Aug 17 00:39:44 CST 2024] OK

如果一切顺利出现上述输出,则表示安装完成。

根据上述输出,安装过程中会进行如下操作:

  • 创建并复制 acme.sh 到你显式指定的主目录(--home): /usr/local/acme.sh/ ,并且工具文件 acme.sh 也放于此,包括所有的证书也将放置在这个文件夹中(--config-home): /usr/local/acme.sh/data
  • 创建别名,例如:在 /root/.bashrc 环境文件中设置 . "/usr/local/acme.sh/acme.sh.env" 环境声明。
  • 创建每日定时任务来检查并更新证书(本次安装已显式忽略)。

acme.sh.env 文件内容参考:

export LE_WORKING_DIR="/usr/local/acme.sh"
alias acme.sh="/usr/local/acme.sh/acme.sh"

或参考官方默认安装 (方式二选一即可)

git clone --depth 1 https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install-online \
--home ~/myacme \
--config-home ~/myacme/data \
--cert-home  ~/mycerts \
--accountemail  "my@example.com" \
--accountkey  ~/myaccount.key \
--accountconf ~/myaccount.conf \
--useragent  "this is my client."

参数释义:

  • --home: 表示安装主目录(默认含 config-home),用于安装 acme.sh。默认情况下,它安装在 ~/.acme.sh
  • --config-home: 证书配置文件目录,需要是一个当前用户可写的文件夹acme.sh 会在这里写入所有文件(主要是证书/密钥的配置文件)。默认情况下,它位于 --home
  • --cert-home: 用于保存你签发的证书 ( 如: /usr/local/acme.sh/data/ )。默认情况下,它保存在 --config-home
  • --accountkey: 是保存你账户私钥的文件。默认情况下,它保存在 --config-home
  • --accountemail: 用于在 Let’s Encrypt 注册账户的电子邮件地址,以便后续收到续期通知邮件。
  • --useragent: 是 acme.sh 发送给 CA 时的 UA 值。
  • --nocron: 安装 acme.sh 后不自动创建定时任务。

Crontab 示例:

0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null

再次提醒:

  • acme.sh 的安装不需要 root 权限,安装过程不会污染已有的系统任何功能和文件,所有的修改都被限制在 ~/.acme.sh/
  • 如果你想在安装的时候指定各种参数,也可以克隆 GitHub 仓库手动安装,更多详细参数可参考官方说明

申请证书 | 手动签发

使用 Let’s Encrypt 作为签发 CA

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

申请证书

./acme.sh --issue \
-d "nestealin.com" \
-d "*.nestealin.com"

参数释义:

  • 默认以第一个 -d 参数域名作为证书主域名,如有多个域名,则继续用 -d 以 SAN 域名进行追加即可,各 CA 证书支持域名的数量上限详见: 申请限制
  • 默认采用”DNS-01“方式验证;
  • 默认采用”ec-256“ KeyLength 申请;如需特殊需求可用 --keylength 参数声明,如: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521 ;
  • 如果需要使用网页验证,需要用 -w /html/path 方式声明;

提示: 后续步骤中的所有证书操作,均以”证书主域名”为准,如有 SAN 域名无需携带。

关于如何联动各 DNS API 实现自动签发,查看: 最佳实践

查看维护中的证书

acme.sh --list

移除证书 | 删除证书

通过如下命令只会移除本地证书文件,不会注销证书

acme.sh --remove -d nestealin.com

移除后提示:

[Sun Aug 18 00:58:18 CST 2024] The domain 'nestealin.com' seems to already have an ECC cert, let's use it.
[Sun Aug 18 00:58:18 CST 2024] nestealin.com has been removed. The key and cert files are in /usr/local/acme.sh/data/nestealin.com_ecc
[Sun Aug 18 00:58:18 CST 2024] You can remove them by yourself.

意味着管理脚本已经移除域名管控,但证书文件仍在本地保留,需要手动移除

证书续期

默认情况下,acme.sh 会在安装后默认添加 crontab 定时任务,每 60 天执行一次自动续期。

当然也可以根据实际情况使用如下命令进行手动续期。

acme.sh --renew -d nestealin.com --force

对于 ECC 证书:

acme.sh --renew -d nestealin.com --force --ecc

ref: acme.sh 使用说明 - ECC 证书

吊销证书

如果确认证书不需要了,可以通过如下命令先向 CA 注销,然后再删除本地证书文件。

首先通过下列命令吊销证书:

acme.sh --revoke -d nestealin.com

出现Revoke success说明吊销成功

此时,只是 CA 注销成功,但证书文件还残留在服务器上,需要通过下列命令移除:

acme.sh --remove -d nestealin.com

然后手动删除本地证书文件:

rm -rf /usr/local/acme.sh/data/nest申请限制期定时任务

```bash
/usr/local/acme.sh/acme.sh --cron --home /usr/local/acme.sh/

升级 acme.sh | 更新 acme.sh

目前由于 ACME 协议和各大 CA 都会频繁地更新, 因此 acme.sh 也要经常更新以保持同步。或在每次执行前手动更新一次。

升至最新版

升级 acme.sh 到最新版:

acme.sh --upgrade

开启自动升级

如果你不想手动升级, 可以开启自动升级:

acme.sh --upgrade --auto-upgrade

之后,acme.sh 就会自动保持更新了。

还原环境

同样地,如果遭遇环境破坏,还可以通过 --force --upgrade 的方式修复:

cd /usr/local/acme.sh
./acme.sh --force --upgrade --nocron --home /usr/local/acme.sh

ref: Synology NAS Guide · acmesh-official/acme.sh Wiki · GitHub

关闭自动升级

你也可以随时关闭自动更新:

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

更换签发 CA

其实,acme.sh 脚本并不只是针对 Let’s Encrypt 单一 CA 进行证书申请,它还支持向其它 CA 申请,如: Buypass、ZeroSSL、SSL.com 和 Google Public CA,而 acme.sh 当前默认的 CA 是 ZeroSSL

ref: Server · acmesh-official/acme.sh Wiki · GitHub

注:

  • 本篇文章使用 Let’s Encrypt 来做讲解;
  • 如果 CA 不变,则命令只需要执行一次,可以不必每次执行 acme.sh 前都进行 --set-default-ca --server xxx
  • Google Public CA 需要按照官方博客申请内测,然后获取 Key;

切换 Let’s Encrypt

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

只需执行一次,切换后在下次执行 acme.sh --issue ... 时默认就会向 Let’s Encrypt 进行申请。

切换 Buypass

acme.sh --set-default-ca --server buypass

切换 ZeroSSL

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

如果已有 ZeroSSL 帐号,可以在后台控制面板拿到 API Key,然后执行如下命令:

apt update
apt install -y jq
curl -s -X POST "https://api.zerossl.com/acme/eab-credentials?access_key=你的API_Key" | jq

输出内容如下:

{
  "success": true,
  "eab_kid": "kid字符串",
  "eab_hmac_key": "hmac_key字符串",
}

然后手动添加帐号:

acme.sh --register-account --server zerossl \
        --eab-kid kid字符串  \
        --eab-hmac-key hmac_key字符串

切换 SSL.com

acme.sh --set-default-ca --server ssl.com

切换 Google Public CA

acme.sh --set-default-ca --server google

更换证书链

如果 ACME CA 提供多个证书链,可以使用 --preferred-chain 选择其中一个。 否则,它将获取默认链。

例如 Let’s Encrypt 在测试环境提供了两种证书链:

Name Default
(STAGING) Pretend Pear X1 No
(STAGING) Bogus Broccoli X2 Yes

可以根据关键名称(Name)任选一种关键字输入:

acme.sh --issue -d example.com .....  --test --preferred-chain  "(STAGING) Pretend Pear X1"
acme.sh --issue -d example.com .....  --test --preferred-chain  "X1"
acme.sh --issue -d example.com .....  --test --preferred-chain  "x1"

ref: Preferred Chain · acmesh-official/acme.sh Wiki · GitHub


注意事项

申请限制

使用 acme.sh 申请证书时,证书的数量受到 Let’s Encrypt 的速率限制的影响。以下是主要的限制信息:

  1. 每个注册域名的证书数量:每周最多可以为每个注册域名申请 50 份证书。例如,如果你的域名是example.com,那么在一周内,你最多可以申请 50 个不同的证书。
  2. 每个账户的订单限制:每个账户每三小时最多可以创建 300 份新订单。每次申请证书时,都会生成一个新订单。
  3. 每份证书的域名数量:每份证书最多可以包含 100 个域名。这意味着你可以在一张证书中为多个域名申请 SSL/TLS 证书。
  4. 续期证书的特殊规则:续期证书不计入每个注册域名的证书数量限制,但每周最多只能续期 5 张重复证书。如果你尝试续期的证书与已有证书的域名列表完全相同,就会触发限制。

目前支持的 CA 厂商特性如下:

CA 厂商 证书有效期 ECC 证书 域名数量 支持通配符 NotAfter 国际化域名
Let’s Encrypt 90 100
ZeroSSL 90 100
Google 90 100
Buypass 180 5 付费
SSL.com 90 2 付费

ref: CA · acmesh-official/acme.sh Wiki · GitHub

小提示: 如果证书域名触发了申请上限,可以尝试增删或更改证书 SAN 域名进行规避。

注: 因为 SSL 证书签发限制只以域名组合(主域名 + SAN 域名)作为唯一判断,例如 SAN 域名的增删都会被认为是一个新的域名组合。

环境变量

  • 如果准备使用脚本二次封装执行,请勿使用 CERT_PATHSSL_CERT_FILE 否则可能引起各种问题;

后记

1. 关于域名验证方式

通常情况下,可以支持两种域名验证方式:

  • 端口验证,有且只能使用 80、443 端口访问测试;
  • TXT 记录验证,通过添加指定域名的 TXT 记录验证归属;

此外,还支持一种隐式验证,即 DNS 别名模式,详情查看: DNS alias mode · acmesh-official/acme.sh Wiki · GitHub

2. 修改 acme.sh 安装目录 | config-home 路径修改

假设初始安装 acme.sh 的 config-home 目录位于 /opt/acme 目录,即执行 acme.sh 的执行脚本位于 /opt/acme/acme.sh 现在想将 config-home 路径修改至 /usr/local/acme.sh 可以通过如下方式修改。

修改流程

迁移目录:

mv /opt/acme /usr/local/acme.sh

修改环境变量:

vim ~/.bashrc
vim ~/.cshrc
vim ~/.tcshrc

一共需要修改上述三个环境变量文件

修改内容前后对照:

# ~/.bashrc
- . "/opt/acme/acme.sh.env"
+ . "/usr/local/acme.sh/acme.sh.env"

# ~/.cshrc
- source "/opt/acme/acme.sh.csh"
+ source "/usr/local/acme.sh/acme.sh.csh"

# ~/.tcshrc
- source "/opt/acme/acme.sh.csh"
+ source "/usr/local/acme.sh/acme.sh.csh"

原理说明

  1. 例如在 bash shell 下时,登陆时默认加载 ~/.bashrc 文件
  2. ~/.bashrc 文件内默认加载 /usr/local/acme.sh/acme.sh.env 环境变量
  3. /usr/local/acme.sh/acme.sh.env 环境变量默认声明 export LE_WORKING_DIR="/usr/local/acme.sh"

注:

  • 如果 config-home 与 home 有单独拆分路径,可能还会有 export LE_CONFIG_HOME="/usr/local/acme.sh/data" 单独的环境变量。
  • ref: GitHub - acme.sh | 4-updating-cert

3. 自动 DNS API 简称及变量速查

服务商名称 服务商简称 所需 API 参数 获取 API 参数地址
cloudxns cx export CX_Key="123456" export CX_Secret="abcdef" 点击访问
dnspod.cn dp export DP_Id="123456" export DP_Key="abcdef" 点击访问
aliyun ali export Ali_Key="123456" export Ali_Secret="abcdef" 点击访问
cloudflare cf export CF_Key="123456" export CF_Email="abc@example.com" 点击访问
linode linode export LINODE_API_KEY="123456" 点击访问
he he export HE_Username="username" export HE_Password="password" he的用户名密码
digitalocean dgon export DO_API_KEY="123456" 点击访问
namesilo namesilo export Namesilo_Key="123456" 点击访问
aws aws export AWS_ACCESS_KEY_ID=123456 export AWS_SECRET_ACCESS_KEY=abcdef 点击访问
namecom namecom export Namecom_Username="username" export Namecom_Token="123456" 点击访问
freedns freedns export FREEDNS_User="username" export FREEDNS_Password="password" freedns的用户名密码
godaddy gd export GD_Key="123456" export GD_Secret="abcdef" 点击访问
yandex yandex export PDD_Token="abcdef" 点击访问

更多 dnsapi 的使用,可以查看文档

4. 转换为p12证书

虽然acme.sh生成的证书可以直接配置到 Nginx、Apache 等等 Web 服务器使用,不过有少数时候如果说想直接配置证书到 Tomcat 中(Spring Boot)那就需要将证书转换成p12格式了!

生成证书后,将证书文件证书密钥文件复制出来,通过openssl命令转换:

openssl pkcs12 -export -in "证书文件路径" -inkey "证书密钥文件路径" -out "指定生成的p12证书文件路径"

执行命令会让你设定p12证书的密码,自行设定即可。

然后在 Spring Boot 配置文件配置如下:

# SSL证书设置
server.ssl.key-store=证书p12文件所在位置
server.ssl.key-store-password=证书密码
server.ssl.keyStoreType=PKCS12

server.ssl.key-store配置项需要以classpath:或者file:开头,一般classpath:开头的表示jar包内路径,Maven 项目中src\main\resources文件夹即可对应为classpath的根目录,而file:对应的是jar包外相对路径或者绝对路径。

# classpath路径
server.ssl.key-store=classpath:ssl.p12

# jar包外路径
server.ssl.key-store=file:ssl/ssl.p12

5. 创建腾讯云 DNSPod Token

DNSPod - 账号中心 | API 密钥 ,在API秘钥 -> DNSPod Token 下创建一个秘钥

接着复制 ID 和 Token,执行如下命令将其配置到环境变量中:

export DP_Id="<DNSPod_Token_ID>"
export DP_Key="<DNSPod_Token>"

6. 创建阿里云 Key 和 Secret

阿里云 - RAM 访问控制 | AccessKey,点击”创建 AccessKey

接着复制 AccessKey ID 和 Secret,执行如下命令将其配置到环境变量中:

export Ali_Key="<AccessKey_ID>"
export Ali_Secret="<AccessKey_Secret>"

References


文章作者: NesTeaLin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 NesTeaLin !
 上一篇
acme.sh实现自动申请证书与自动部署群晖DSM acme.sh实现自动申请证书与自动部署群晖DSM
通过acme.sh完成SSL证书的自动申请与自动部署到群晖DSM,并在定时任务的支持下完成自动化续期及更新操作。
2024-09-01
下一篇 
Nginx中server_name的一些无用冷知识 Nginx中server_name的一些无用冷知识
简单介绍Nginx中server_name的匹配顺序及无意义域名的"误区";对于Nginx泛域名/兜底域名的基本配置说明;支持国际化域名(中文域名)的配置。
2024-04-06
  目录