使用acme.sh生成免费https证书

主要特性:

  • 纯shell脚本开发,其完整实现了acme协议,无过多依赖
  • 支持ECDSA证书
  • 支持泛域名证书
  • 兼容Bash、dash、sh
  • 支持自动续期,定时任务续期提醒
  • 简单易上手
  • 不会修改web服务器配置,需自行配置

It’s probably the easiest & smartest shell script to automatically issue & renew the free certificates.

官网:https://acme.sh

安装

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

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

或者:

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

中国区如果无法安装可以克隆项目的github或gitee地址

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

安装完后需要source环境变量,或者重开一个终端才能使用acme.sh命令。

acme.sh程序安装在用户目录,以root用户为例,目录在/root/.acme.sh,安装成功后会自动创建定时任务,用于更新即将过期的证书。

生成证书

切换CA

如果不想用zero ssl,可以切换默认CA为Let’s Encrypt:

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

常见的验证模式

webroot模式

webroot模式要求在服务器上已经运行了http服务,并且可以通过公网访问,该模式的好处是,你无需在申请证书的过程中停止web服务,因此,该模式也是推荐使用的模式。验证完毕后,acme.sh会清除这些临时生成的文件。

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

申请证书时如果报无法验证的错误,请在nginx 域名配置文件domain.confserver里面加上这段配置:

1
2
3
4
location ^~ /.well-known/acme-challenge/ {
default text/plain;
root /home/webroot;
}

nginx模式

acme.sh会在域名验证完毕后自动将nginx配置还原,不会修改用户的设置

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

另外acme可能无法识别nginx配置文件位置,此时可以指定nginx配置文件目录

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

DNS自动模式

这种模式可以使用域名解析商提供的api自动为域名添加txt记录以完成域名所有权验证,不同于DNS手动模式,DNS自动模式支持自动更新证书。这也是我推荐使用的模式,因为我要生成泛域名证书。

acme.sh目前支持cloudflare,dnspod,aliyun,cloudxns,godaddy以及ovh等数十种解析商,具体可查看~/.acme.sh/dnsapi目录,不会的看这里:如何使用DNS API获取证书

以阿里云为例:

  1. 登录DNS服务商控制台,获取AccessKeyId和AccessKeySecret,地址:https://ram.console.aliyun.com/manage/ak

  2. 添加环境变量,vim ~/.bashrc

1
2
export Ali_Key="<key>"
export Ali_Secret="<secret>"
  1. 生成泛域名证书
1
2
# 只适用dns模式
acme.sh --issue --dns dns_ali -d example.com -d '*.example.com'

证书生成成功后会有SUCCESS提示

生成ECC证书

目前大部分的证书都是使用RSA非对称加密算法,但一些CA,例如letsencryption、zerossl等,已经支持颁发性能更加优良的ECC非对称加密算法证书。

1
acme.sh --issue -d example.com -d example1.com --dns dns_ali --keylength ec-256

keylength可用的值有:

  1. ec-256 (prime256v1, “ECDSA P-256”, which is the default key type)
  2. ec-384 (secp384r1, “ECDSA P-384”)
  3. ec-521 (secp521r1, “ECDSA P-521”, which is not supported by Let’s Encrypt yet.)
  4. 2048 (RSA2048)
  5. 3072 (RSA3072)
  6. 4096 (RSA4096)

生成ecc泛域名证书

1
2
# 引号不能忽略
acme.sh --issue -d example.com -d '*.example.com' --dns dns_ali --keylength ec-256

生成证书失败

这三种模式我都用过,其中使用nginx或webroot模式,可能会失败,出现如下错误:

1
2
3
...
Verify error: xx.xx.xx.xx: Fetching http://XXXXXX.com/.well-known/acme-challenge/Plq5aNPQq1-xnNjxqxUo06jHQltZRoW6_m9apW74oxA: Timeout during connect (likely firewall problem)
...

这时推荐把ca切换到letsencrypt,并且升级acme版本,重新申请后如果还是同样错误,建议使用dns模式。

部署证书

部署前必须自己更新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 443 ssl;
server_name example.com;
root /workspace/www;

ssl_certificate cert/example.com.fullchain.cer;
ssl_certificate_key cert/example.com.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

location / {
index index.html;
expires -1;
# try_files $uri /index.html 403;
}

}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
}
listen 80;
server_name example.com;
return 404;
}

检查无误后我们可以通过--install-cert参数复制证书文件到nginx指定目录

1
acme.sh --install-cert -d example.com --key-file /etc/nginx/cert/example.com.key --fullchain-file /etc/nginx/cert/example.com.fullchain.cer --reloadcmd "service nginx force-reload"

reloadcmd是用于重新加载配置,由于reload不会加载证书,所以需要force-reload,它其实是先stop再start,也可以restart,如果nginx没有注册成service,可以指定其路径。

acme有一个好处是它会记录一些命令中的信息,用于未来自动更新证书,它存储在这里:

1
~/.acme.sh/example.com/example.com.conf

查看证书

列出已生成的证书

1
acme.sh --list

命令打印如下信息,最后一列Renew表示证书下一次更新的时间

1
2
Main_Domain  KeyLength  SAN_Domains    CA           Created               Renew
example.com "ec-256" *.example.com ZeroSSL.com 2023-08-19T05:02:19Z 2023-10-17T05:02:19Z
1
2
# 查看证书具体信息
acme.sh --info -d example.com

更新证书

默认情况下acme.sh会自动更新即将过期的证书,不过我们可以手动更新

1
2
3
4
5
6
7
acme.sh --renew -d example.com
# 如果是ecc证书:
acme.sh --renew -d example.com --ecc
# 强制更新证书
acme.sh --renew -d example.com --force --ecc
# 停止更新证书,不删除证书文件
acme.sh --remove -d example.com [--ecc]

更新acme.sh

1
2
3
4
5
acme.sh --upgrade
# 开启自动更新
acme.sh --upgrade --auto-upgrade
# 关闭自动更新
acme.sh --upgrade --auto-upgrade 0