acme.sh用于生成免费的ssl证书,其完整实现了acme协议,并且由纯Shell脚本语言编写,没有过多的依赖项,安装和使用都非常方便。

  Github: https://github.com/acmesh-official/acme.sh

目录

ACME申请SSL证书

acme.sh

1. 支持的CA

> ZeroSSL.com CA(default):90天
> Letsencrypt.org CA:90天
> BuyPass.com CA:180天
> SSL.com CA
> Pebble strict Mode
> Any other RFC8555-compliant CA

2. 支持的运行模式

> Webroot mode
> Standalone mode
> Standalone tls-alpn mode
> Apache mode
> Nginx mode
> DNS mode
> DNS alias mode
> Stateless mode

安装ACME

1.在线安装

直接通过curl下载安装脚本并自动执行:

1
curl https://get.acme.sh | sh -s email=my@example.com

或者使用wget:

1
wget -O -  https://get.acme.sh | sh -s email=my@example.com

如果acme.sh使用zeroSSL CA,则这里的-s参数指定的邮箱可以关联到已有的zeroSSL账号。关联成功后,通过acme.sh生成的zeroSSL证书会在zeroSSL网站的控制面板上显示。

2.或者通过git安装

1
2
3
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install -m my@example.com

3.安装说明

安装程序将执行 3 个操作:
 a.创建并复制acme.sh到您的主目录 ( $HOME): ~/.acme.sh/。所有证书也将放置在此文件夹中。
 b.创建别名acme.sh=~/.acme.sh/acme.sh
 c.如果需要,创建每日 cron 作业以检查和更新证书。

crontab示例:

普通用户:

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

root用户:

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

申请证书

1.使用说明

acme.sh的命令格式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
acme.sh 命令 ... [参数] ...

  -h, --help : 显示帮助信息
  -v, --version : 显示版本信息
  -f, --force : 强制安装、强制证书更新
  --upgrade : 手动更新
  --auto-upgrade : 开启自动更新
  --auto-upgrade 0 : 关闭自动更新
  --uninstall : 卸载
  --list : 列出证书
  --issue : 申请证书
  -r, --renew : 更新证书
  --revoke : 吊销证书
  --remove : 删除证书
  --install-cert : 安装证书
  --reloadcmd <command> : 设置重启命令 

以域名example.com为例,生成的证书将放置在以下目录:
 ~/.acme.sh/example.com/
该目录之下是证书、私钥等文件以及一些其它配置文件:
 证书文件: example.com.cer
 私钥: example.com.key
 中间证书: ca.cer
 证书链:fullchain.cer
 配置文件:example.com.conf(上次申请使用的参数会自动保存到该文件)

2.切换CA

当前acme.sh使用的默认CA机构为zeroSSL,通过--set-default-ca命令,可以修改默认的CA机构,该命令使用--server参数来指定CA机构名称。

切换默认CA为Let’s Encrypt:

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

更换默认CA为ZeroSSL:

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

3.webroot模式

webroot模式要求在服务器上已经运行了http服务,并且可以通过公网访问,该模式的好处是,你无需在申请证书的过程中停止web服务,因此,该模式也是推荐使用的模式。

使用webroot模式申请证书时,acme.sh会在网站对应域名的webroot目录下生成域名验证文件, 然后通过公网访问之,以验证对域名的所有权。验证完毕后,acme.sh会清除这些临时生成的文件。

申请证书使用–issue命令:

1
acme.sh --issue -d example.com -d test.com -w /home/webroot

-d参数指定域名,多个域名使用多个-d参数,第一个-d参数指定的域名即证书的主体名称,其它-d参数指定的域名为证书的可选主体名称。

-w参数指定的是域名的webroot目录,以example.com为例,-w参数的值即是http://example.com对应的webroot目录。如果使用多个-d参数同时指定了多个域名,则所有这些域名必须对应同一个webroot目录;另外,当前系统用户必须具有webroot目录的写入权限。

常见错误:

a. -w参数指定的路径有误

b. 域名对应的站点无法通过公网访问(防火墙阻断、http服务没有运行等)

出现以上错误,则acme.sh指定的CA将无法下载到acme.sh生成的域名验证文件,并在重试30次之后报出Timeout错误:

1
2
3
...
Processing, The CA is processing your order, please just wait. (29/30)
example.com:Timeout

c. 另外,如果当前系统用户没有-w参数指定的webroot目录的写入权限,将导致acme.sh无法创建域名验证文件。

-w参数进阶:

需要进一步说明的时,对于-w参数,其实有着更加准确的解释。

在验证域名的所有权时,具体来说,acme.sh会在网站的webroot目录下创建.well-known目录,然后再在其中生成验证文件。因此,-w参数指定的路径实际为域名之下,/.well-known位置对应的路径。

例如,对于站点:

Example Domain

-w对应的路径为以下链接对应的目录:

http://example.com/.well-known

即acme.sh域名验证的原理是:acme.sh在-w参数指定的路径下创建.well-known文件夹,并在其中生成域名验证文件;然后,acme.sh对应的CA通过访问http://example.com/.well-known链接,到-w参数指定的路径下去寻找域名验证文件。

以下面的nginx配置为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server {
       listen 80;
       server_name example.com;
       root /home/wwwroot/example;

       location /.well-known {
              root /home/wwwroot/html;
       }
      
       location ~* .(gif|jpg|jpeg|png|bmp)$ {
              expires 90d;
       }
}

example.com站点的webroot目录为:

/home/wwwroot/example

而location定义的/.well-known位置对应的webroot目录为:

/home/wwwroot/html

那么,通过webroot模式为站点申请证书时,-w参数指定的路径不是server配置段指定的webroot目录:/home/wwwroot/example,而应该是location配置段定义的/.well-known位置对应的webroot目录:/home/wwwroot/html。

最终,为站点example.com申请证书的命令为:

1
acme.sh --issue -d example.com -w /home/wwwroot/html

利用.well-known为多个域名同时申请证书

正如前文所述,当使用多个-d参数同时为多个域名申请证书时,要求这些域名必须对应相同的webroot目录。此处再结合.well-known的特性可知,这些域名实际上没有必要对应相同的webroot目录,只需要这些域名之下的/.well-known位置对应的路径相同就可以了。

因此,在同时为多个域名申请证书时,我们可以合理配置使用同一个证书的各个站点的/.well-known位置,令其指向同一目录即可,而不必去修改每个站点的webroot目录为同一路径,从而可以降低这一要求对业务配置的影响。

以下面的nginx配置为例:

 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
server {
       listen 80;
       server_name example.com;
       root /home/wwwroot/example;

       location /.well-known {
              root /home/wwwroot/html;
       }

       location ~* .(gif|jpg|jpeg|png|bmp)$ {
              expires 90d;
       }
}

server {
       listen 80;
       server_name test.com;
       root /home/wwwroot/test;

       location /.well-known {
              root /home/wwwroot/html;
       }

       location ~* .(gif|jpg|jpeg|png|bmp)$ {
              expires 90d;
       }
}

当同时为域名example.com和test.com申请证书时,它们可以使用不同的webroot目录,只需要域名之下的/.well-known位置对应相同的路径即可,为它们申请证书的命令为:

1
acme.sh --issue -d example.com -d test.com -w /home/wwwroot/html

4. nginx模式

如果服务器上运行的http服务为nginx,并且当前系统用户具有修改nginx配置的权限,则可以通过nginx模式生成证书。

通过--nginx参数使用nginx模式:

1
acme.sh --issue --nginx -d example.com -d www.example.com

该命令相比于webroot模式增加了--nginx参数,同时省略了-w参数。该命令会自动修改nginx配置并重新加载之以适配域名的验证要求,所以无需-w参数。另外,acme.sh会在域名验证完毕后自动将nginx配置还原,因此,nginx配置最终并没有被修改。

特殊的情况是acme.sh可能无法识别nginx配置文件所在位置,此时,可以明确指定:

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

5.apache模式

与nginx模式原理相同,通过--apache参数使用apache模式:

1
acme.sh --issue --apache -d example.com -d www.example.com

6. standalone模式

如果服务器的tcp 80端口空闲可用,则可通过standalone模式生成证书。该模式下,acme.sh 自己运行一个webserver, 临时监听在80 端口, 完成验证:

1
acme.sh --issue --standalone -d example.com -d www.example.com

如果服务器已经占用了80端口,可以通过--httpport参数使用80以外的端口:

1
acme.sh --issue --standalone -d example.com -d www.example.com --httpport 88

需要指出的是,standalone模式下,acme.sh会自己运行一个webserver,依赖的是socat,需要提前安装:

1
yum install socat

7. standalone ssl模式

这是另一个standalone模式,使用了ssl,要求服务器的tcp 443端口空闲可用:

1
acme.sh --issue --alpn -d example.com -d www.example.com

可以通过--tlsport参数使用443以外的端口:

1
acme.sh --issue --alpn -d example.com -d www.example.com --tlsport 8443

8.DNS API模式

DNS 模式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证,acme.sh 目前支持 cloudflare, dnspod, cloudxns, godaddy 以及 ovh 等数十种解析商的自动集成。

如果您的 DNS 提供商支持 api 访问,我们可以使用该 api 自动颁发证书,无需手动执行任何操作.

官方文档: https://github.com/acmesh-official/acme.sh/wiki/dnsapi

9.DNS手动模式:

官方文档: https://github.com/acmesh-official/acme.sh/wiki/dns-manual-mode

如果您的 DNS 提供商不支持任何 api 访问,您可以手动添加 txt 记录。

1.生成txt记录

1
acme.sh --issue -d example.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

得到如下输出:

1
2
3
4
5
6
...
Add the following TXT record:
Domain: '_acme-challenge.example.com'
TXT value: 'jdwEz-S92f2o0Sjbd1KfA4O5L1MeFL2QE1F2PFuOIHo'
Please be aware that you prepend _acme-challenge. before your domain
so the resulting subdomain will be: _acme-challenge.example.com

2.请将TXT记录添加到DNS记录中,每次续订证书时都需要此步骤。使用DNS api模式,可以自动执行此步骤。

3.使用--renew更新证书

1
acme.sh --renew -d example.com --yes-I-know-dns-manual-mode-enough-go-ahead-please

注意,这是DNS手动模式,不能自动更新。更新证书时,您必须手动将新的 txt 记录添加到您的域中。

如需自动更新,请改用 DNS API 模式。

10.ECC证书

目前最常用的密钥交换算法有 RSA 和 ECDHE:

  • RSA历史悠久,兼容性好,但计算相对较慢;

  • ECDHE使用了ECC算法,计算速度快,但兼容性相对较差;

内置ECDSA公钥的证书一般被称之为ECC证书,内置RSA公钥的证书称为RSA证书;ECC算法在计算复杂度远小于RSA,但是却能在更小的长度上得到RSA的同款安全等级,一般认为 256 位 ECC Key 在安全性上等同于 3072 位 RSA Key,所以ECC证书不仅体积小,运算速度也更快。

诚然,ECC证书有压倒性的优势,但是由于历史原因,它在旧系统的兼容性上存在不少问题,比如XP及之前的Windows系统都原生不支持(火狐浏览器除外),但是如果你不打算兼容老系统,使用ECC无疑更有优势。

目前acme.sh支持以下三类可选长度:

  • ec-256(推荐使用)

  • ec-384

  • ec-521(不完善,Let’s Encrypt 尚不支持)

这里使用ec-256,仅需添加--keylength参数

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

申请ECC证书后,其他命令需要添加 –ecc 参数:

1
2
3
4
5
6
7
8
# 更新证书
acme.sh --renew -d example.com --force --ecc
# 安装证书
acme.sh --install-cert -d example.com ... --ecc
# 吊销证书
acme.sh --revoke -d example.com --ecc
# 移除证书
acme.sh --remove -d example.com --ecc

11.安装证书

apache示例:

1
2
3
4
5
acme.sh --install-cert -d example.com \
--cert-file      /path/to/certfile/in/apache/cert.pem  \
--key-file       /path/to/keyfile/in/apache/key.pem  \
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd     "systemctl restart httpd"

nginx示例:

1
2
3
4
acme.sh --install-cert -d example.com \
--key-file       /path/to/keyfile/in/nginx/key.pem  \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd     "systemctl restart nginx"