如何使用 acme 实现 ssl 免费证书到期自动更新

437 阅读5分钟

一、安装acme

首先下载安装 acme,后面的 email修改为自己的用于收取SSL证书相关的消息,acme 默认会安装在~/.acme.sh/目录下。

  • 在线安装
curl https://get.acme.sh | sh -s email=mymail@mail.com

或者

wget -O - [https://get.acme.sh](https://get.acme.sh/) | sh -s <email=my@example.com
  • git安装
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install -m my@example.com

如果上述命令太慢或失败(网络原因),可尝试以下国内备用地址:

curl  https://gitcode.net/cert/cn-acme.sh/-/raw/master/install.sh?inline=false | sh -s email=my@example.com
  • 安装完成后重启终端生效,使用acme.sh -v获取到版本信息即安装成功
$ acme.sh -v
https://github.com/acmesh-official/acme.sh
v3.0.8

二、 修改SSL证书服务商

默认SSL 证书服务商为 ZeroSSL,申请过程比较容易出错建议修改为letsencrypt,不修改也没事。

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

三、证书申请

证书申请过程需要一个域名验证操作,acme 支持两种验证方式:http(文件) 验证和 dns 验证,首先说 dns 验证方式,dns 验证可以手动添加CNAME记录也可以通过 dns 厂商提供的 api 进行添加。

dns验证 不需要依赖HTTP服务器环境,不需要公网IP。DNS 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证。

注意:手动添加DNS记录的方式将无法自动更新证书,因为每次都需要手动再次重新解析验证域名所有权。
注意:如果需要生成泛域名(*.a.com)的证书,不能使用HTTP认证域名,需要改用DNS认证的方式,本
  • 手动添加的
acme.sh  --issue  --dns -d mydomain.com \
 --yes-I-know-dns-manual-mode-enough-go-ahead-please

将上述txt解析添加到域名管理面板中

在域名上添加一条 txt 解析记录(手动添加记录,或通过api自动添加记录)

  • ** dnsapi如何自动添加**

acme.sh 目前支持 [cloudflare]、[dnspod] 等数十种解析商的自动集成,详见:How to use DNS API - GitHub

阿里云的域名系统也在支持之列。登录阿里云获取有 DNS 操作权限的用户的API令牌(Key和Secret),可以直接使用主帐号的令牌(右上角 AccessKey 管理),也可以使用 RAM 子帐号的令牌:

  • 进入 RAM 访问控制(可直接在右上角搜索:访问控制)
  • 进入 RAM 中的身份管理中的用户组(如果已创建过用户,可直接最后一步)
  • 创建用户组,为其新增 AliyunDNSFullAccess 授权
  • 点击左侧用户菜单并创建用户 >访问方式一定要勾选 Open API 调用访问
  • 将新建的用户添加到前面创建的用户组
  • 到认证管理中创建 AccessKey,创建成功后建议直接导出,防止忘了

执行下面命令导向全局环境变量然后生成证书

export Ali_Key="JIDJ5fkdH86KHd6Kh7ggD8DK"
export Ali_Secret="2adfkH6Kjdh7fdg6JHjk7fekl2GDJFB"

acme.sh --issue --dns dns_ali -d example.com -d www.example.com --debug
  • 可以用 -d 指定多个域名,共用一个证书;
  • 带上 --debug 参数,可以看到更详细的执行情况,出错时方便找问题;
  • 生成证书期间acme会请求80端口,如果需要指定端口可使用--httpport
  • 如果申请通配符证书则在在域名前面加上*,如*.example.com

如果成功,将提示”Cert success.“并把证书位置打印出来(证书保存到 ~/.acme.sh/example.com 目录)。生成证书时指定的参数、下次更新日期(两个月后)等信息将会被自动记录在 ~/.acme.sh/example.com/example.com… 中,令牌信息也保存在 ~/.acme.sh/account.conf 中,以便将来自动更新证书。

如果不成功,查日志(~/.acme.sh/acme.sh.log)定位。可能的原因有:

  1. 域名的TXT记录尚未全网更新。比如Namesilo更新比较慢,1000秒过去了仍然查不到,失败几次后放弃;可以在本地(windows:ipconfig /flushdns 和 nslookup -qa=txt _acme-challenge.www.example.com)上手工检查域名txt记录的更新情况;
  2. 域名记录未清空,还存在TXT记录。如果第一次不成功,要等待TTL时间再试,因为acme.sh将添加相同的二级域名(_acme-challenge.www),但值又不一样。

因为 tomcat 使用 cer (公钥)和 key (私钥)合并一体且加密的 pfx 格式的证书,所以还要导出为 pfx 格式,使用 --password 选项指定加密的密码(该密码要设置到目标服务器的配置文件中):

acme.sh --to-pkcs12 -d example.com --password 7dK6h1BdWd9 --debug

导出成功将提示 Success,并告知导出的pfx路径(在同一域名目录下),同时将会自动记录加密密钥,以便下次自动更新证书时使用。

http验证

acme.sh --issue --webroot /data/example/mankind-test/www -d mk.example.com
  • /path/to/webroot 是在域名对应的服务器(ip)上访问域名( http://域名:80/ ) 对应的目录,
  • -d 指向域名
  • example
  listen      80;
  server_name    mk.example.com;
  index index.html;
  root /data/example/mankind-test/www;
  
  }
  

三、证书安装

  • 默认生成的证书都会放在安装目录下:~/.acme.sh/。然而,不要在服务器中直接引用该目录下的证书文件,也不要手动将证书文件拷贝到具体的 web 服务器中,因为手动拷贝会导致之后的证书更新流程无法完全自动化。
  • 正确的方式是使用 acme.sh 的安装证书命令,这样 acme.sh 会自动将证书文件拷贝到指定的目录中,并记录下拷贝命令。在之后的自动更新过程中,acme.sh 会执行该拷贝步骤,从而实现证书更新流程的完全自动化。

代码语言:txt

**复制

acme.sh --install-cert -d xxx \
		--cert-file xxx \
		--key-file xxx \
		--fullchain-file xxx\
		--reloadcmd xxx  // 服务重新加载命令

  • 由于我使用的是 docker 运行的 nginx ,因此我的重载命令是 docker container restart nginx,如果你直接使用 nginx 可以使用命令 service nginx force-reload

使用 SSL 证书

  • 上述命令会将证书按照在我们的指定目录,接下来我们只需要在 web 服务器中使用即可。
  • 以 nginx 为例:

代码语言:txt

**复制

server {
  listen       443 ssl;
  ssl_certificate      /etc/nginx/cert_file/fullchain.pem;
  ssl_certificate_key  /etc/nginx/cert_file/key.pem;
  # ...
}