ACME的使用经验

ACME 简介

ACME 是一个自动管理证书的程序。 rfc8555 是 ACME 的 rfc 。

ACME
Automatic Certificate Management Environment
自动 证书 管理 环境

ACME 有很多种实现,这篇文章描述的是 acme.sh 的使用。

acme.sh 的 GitHub 仓库地址

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

acme.sh 的文档

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

中文说明
https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E
https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials#%E4%B8%AD%E6%96%87

ACME 下载和安装

直接下载安装

curl https://get.acme.sh | sh -s email=my@example.com
curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m  my@example.com

从源码安装

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

安装完后把 .acme.sh 文件夹复制到用户的根目录下,类似这样的路径

~/.acme.sh/
/root/.acme.sh/

为 acme.sh 创建一个别名

其实把安装后的目录复制到用户的根目录和创建别名都不是必须的,但为了贴合文档的教程和方便使用,最好还是这样做

申请证书

运行这句命令申请证书, 运行这句命令时,http服务需要已经启用,并且是监听 80 端口的, 注意修改域名和站点根目录的路径

acme.sh --issue -d www.example.com --webroot /home/wwwroot/example.com/

如果加上 --standalone 参数, acme.sh 能临时运行一个 webserver, 临时听在80 端口,但这是使用 socat 实现的,所以要先安装好 socat

acme.sh --issue -d www.example.com --webroot /home/wwwroot/example.com/ --standalone

申请证书命令运行后会输出证书生成的位置,这个位置通常是

~/.acme.sh/www.example.com_ecc/cert.pem
~/.acme.sh/www.example.com_ecc/www.example.com.key
~/.acme.sh/www.example.com_ecc/fullchain.cer

上面的命令是使用 HTTP 验证, DNS 验证因为笔者没有用到就不记录了

安装证书

acme.sh --install-cert -d www.example.com \
    --cert-file      /c/nginx/crt/www.example.com/cert.pem  \
    --key-file       /c/nginx/crt/www.example.com/www.example.com.key \
    --fullchain-file /c/nginx/crt/www.example.com/fullchain.cer \
    --reloadcmd     "service nginx force-reload"

续签证书

要先运行过安装证书的命令才能使用续签证书的命令。 如果没有,那么要重新申请一次证书,然后把证书复制到对应的目录里。 多数情况下,续签证书的命令会加到定时任务里。

一般的命令

~/.acme.sh/acme.sh --cron --home "/root/.acme.sh" > /dev/null

写成 cron 表达式

0 2 * * * /bin/bash /root/.acme.sh/acme.sh --cron --home "/root/.acme.sh" > /dev/null

这个命令除了用于续签证书外,还用于自动更新

其它常用的命令

查看全部证书

acme.sh --list

产看全部证书,包括已过的

acme.sh --list-archive

查看已安装证书的信息

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

更新

acme.sh --upgrade

开启自动更新

acme.sh --upgrade --auto-upgrade

关闭自动更新

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

在 Windows 环境下使用 ACME

acme.sh 文档里关于 Windows 环境的描述

https://github.com/acmesh-official/acme.sh/wiki#4-how-to-run-on-windows-with-cygwin-or-git-bash

自动续签证书的定时任务可以使用 windows 计划任务,但这样的写法,任务运行时会有一个黑框弹出来 (笔者试了很多方法依然无法隐藏这个黑框,在服务器里每晚运行一次的话应该没关系的吧,即使有黑框也是一闪而过)

Register-ScheduledTask -TaskName "acme_cron" -AsJob -Trigger (New-ScheduledTaskTrigger -Daily -At "2:00 AM") -Action (New-ScheduledTaskAction -Execute "PowerShell" -Argument "-Nolog -NonInteractive -WindowStyle Hidden -Command `"C:\Users\a\Git\usr\bin\bash.exe -l /c/Users/a/.acme.sh/acme.sh --cron --home /c/Users/a/.acme.sh`"")

以 nginx 为例子

假设已经安装好 acme.sh 和 nginx

  1. 在 nginx 安装目录下新建一个名为 crt 的目录, 在 crt 目录下再新建一个以域名为名的目录
  2. 直接启动 nginx
    • nginx 的配置文件里一般会有一个默认的站点,这个站点的目录一般在 nginx 的安装目录下的 html 目录
  3. 运行申请证书的命令,在 nginx 默认的站点更目录里运行这句
    acme.sh --issue -d www.example.com --webroot $(pwd)
    
  4. 在 nginx 的安装目录里新建一个名为 restart.ps1 的文件并写入以下内容,这个脚本主要是用于重启 nginx 的,要注意 powershell 的执行策略
    # 切换到批处理文件所在的目录
    Set-Location $PSScriptRoot
    
    # 显示批处理文件所在的目录
    Write-Output $PSScriptRoot
    
    # 停止 nginx 服务
    ./nginx.exe -s quit
    
    # 等待 6 秒
    Start-Sleep -Seconds 6
    
    # 强制结束 nginx 进程及其子进程
    Get-Process -Name nginx | Stop-Process -Force
    
    # 测试 nginx 配置文件
    ./nginx.exe -T
    
    # 启动 nginx 服务
    Start-Process -FilePath powershell -ArgumentList "-NonInteractive", "-command", "./nginx.exe"
    
  5. 运行安装证书的命令
    acme.sh --install-cert -d www.example.com \
        --cert-file      /c/Users/a/nginx/crt/www.example.com/cert.pem  \
        --key-file       /c/Users/a/nginx/crt/www.example.com/www.example.com.key \
        --fullchain-file /c/Users/a/nginx/crt/www.example.com/fullchain.cer \
        --reloadcmd     "powershell \"C:\Users\a\nginx\restart.ps1\""
    
  6. 在 nginx 的配置文件里加上这一段
    server {
        listen       80;
        server_name  www.example.com;
    
        listen       443 ssl http2;
        ssl_certificate  ./crt/www.example.com/fullchain.cer;
        ssl_certificate_key ./crt/www.example.com/www.example.com.key;
    
        access_log  logs/www.example.com.access.log;
        error_log  logs/www.example.com.error.log;
    
        if ($scheme = 'http') {
            return 302 https://$host$request_uri;
        }
    
        location / {
            root   C:/User/a/www.example.com; # 这是站点根目录的路径
            index  index.html index.htm;
        }
    }