官网:
Github: https://github.com/acmesh-official/acme.sh
Wiki: https://github.com/acmesh-official/acme.sh/wiki
acme.sh用于生成免费的ssl证书,其完整实现了acme协议,并且由纯Shell脚本语言编写,没有过多的依赖项,安装和使用都非常方便。
> ZeroSSL.com CA(default):90天
> Letsencrypt.org CA:90天
> BuyPass.com CA:180天
> SSL.com CA
> Pebble strict Mode
> Any other RFC8555-compliant CA
> Webroot mode
> Standalone mode
> Standalone tls-alpn mode
> Apache mode
> Nginx mode
> DNS mode
> DNS alias mode
> Stateless mode
直接通过curl下载安装脚本并自动执行:
curl https://get.acme.sh | sh -s [email protected]
或者使用wget:
wget -O - https://get.acme.sh | sh -s [email protected]
如果acme.sh使用zeroSSL CA,则这里的-s参数指定的邮箱可以关联到已有的zeroSSL账号。关联成功后,通过acme.sh生成的zeroSSL证书会在zeroSSL网站的控制面板上显示:
Free SSL Certificates and SSL Tools - ZeroSSL
对于zerossl官网,需要指出的是,用户可以在控制台直接申请证书,但免费用户最多只能申请3个,而使用ACME申请zeroSSL证书则没有数目限制。
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
./acme.sh --install -m [email protected]
a. 部署acme.sh程序到用户文件夹
($HOME): ~/.acme.sh/
以root用户为例,acme.sh的安装目录为:
/root/.acme.sh/
acme.sh的根目录是一个隐藏文件夹.acme.sh,核心脚本文件为:
($HOME): ~/.acme.sh/acme.sh
b. 为脚本执行文件创建别名
acme.sh=~/.acme.sh/acme.sh
注意,别名需要重启终端后才能生效。
c. 创建一个每日执行的cron任务,用于自动更新即将过期的证书。
示例,通过crontab -l命令查看证书更新任务计划:
0 0 * * * "/home/user/.acme.sh"/acme.sh --cron --home "/home/user/.acme.sh" > /dev/null
如果是root用户:
40 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
在该计划任务下,当证书剩余有效期不足30天时,证书将会被自动更新。
更高级的安装选项请参考:
https://github.com/Neilpang/acme.sh/wiki/How-to-install
安装过程不会污染已有的系统任何功能和文件, 所有的修改都限制在安装目录中: ~/.acme.sh/
当对acme.sh的功能有疑问时,请参考帮助信息:
acme.sh -h
卸载后,cron计划任务也会被移除:
acme.sh --uninstall
以域名example.com为例,生成的证书将放置在以下目录:
~/.acme.sh/example.com/
该目录之下是证书、私钥等文件以及一些其它配置文件:
证书文件: example.com.cer
私钥: example.com.key
中间证书: ca.cer
证书链:fullchain.cer
当前acme.sh使用的默认CA机构为zeroSSL,通过--set-default-ca命令,可以修改默认的CA机构,该命令使用--server参数来指定CA机构名称。
切换默认CA为Let's Encrypt:
acme.sh --set-default-ca --server letsencrypt
更换默认CA为ZeroSSL:
acme.sh --set-default-ca --server zerossl
webroot模式要求在服务器上已经运行了http服务,并且可以通过公网访问,该模式的好处是,你无需在申请证书的过程中停止web服务,因此,该模式也是推荐使用的模式。
使用webroot模式申请证书时,acme.sh会在网站对应域名的webroot目录下生成域名验证文件, 然后通过公网访问之,以验证对域名的所有权。验证完毕后,acme.sh会清除这些临时生成的文件。
申请证书使用--issue命令:
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错误:
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配置为例:
server {
listen 80;
server_name example.com;
root /home/site/example;
location /.well-known {
root /home/site/dancen;
}
location ~* .(gif|jpg|jpeg|png|bmp)$ {
expires 90d;
}
}
example.com站点的webroot目录为:
/home/site/example
而location定义的/.well-known位置对应的webroot目录为:
/home/site/dancen
那么,通过webroot模式为站点申请证书时,-w参数指定的路径不是server配置段指定的webroot目录:/home/site/example,而应该是location配置段定义的/.well-known位置对应的webroot目录:/home/site/dancen。
最终,为站点example.com申请证书的命令为:
acme.sh --issue -d example.com -w /home/site/dancen
● 利用.well-known为多个域名同时申请证书
正如前文所述,当使用多个-d参数同时为多个域名申请证书时,要求这些域名必须对应相同的webroot目录。此处再结合.well-known的特性可知,这些域名实际上没有必要对应相同的webroot目录,只需要这些域名之下的/.well-known位置对应的路径相同就可以了。
因此,在同时为多个域名申请证书时,我们可以合理配置使用同一个证书的各个站点的/.well-known位置,令其指向同一目录即可,而不必去修改每个站点的webroot目录为同一路径,从而可以降低这一要求对业务配置的影响。
以下面的nginx配置为例:
server {
listen 80;
server_name example.com;
root /home/site/example;
location /.well-known {
root /home/site/dancen;
}
location ~* .(gif|jpg|jpeg|png|bmp)$ {
expires 90d;
}
}
server {
listen 80;
server_name test.com;
root /home/site/test;
location /.well-known {
root /home/site/dancen;
}
location ~* .(gif|jpg|jpeg|png|bmp)$ {
expires 90d;
}
}
当同时为域名example.com和test.com申请证书时,它们可以使用不同的webroot目录,只需要域名之下的/.well-known位置对应相同的路径即可,为它们申请证书的命令为:
acme.sh --issue -d example.com -d test.com -w /home/site/dancen
如果服务器上运行的http服务为nginx,并且当前系统用户具有修改nginx配置的权限,则可以通过nginx模式生成证书。
通过--nginx参数使用nginx模式:
acme.sh --issue --nginx -d example.com -d www.example.com
该命令相比于webroot模式增加了--nginx参数,同时省略了-w参数。该命令会自动修改nginx配置并重新加载之以适配域名的验证要求,所以无需-w参数。另外,acme.sh会在域名验证完毕后自动将nginx配置还原,因此,nginx配置最终并没有被修改。
特殊的情况是acme.sh可能无法识别nginx配置文件所在位置,此时,可以明确指定:
acme.sh --issue -d example.com --nginx /etc/nginx/nginx.conf
如果服务器的tcp 80端口空闲可用,则可通过standalone模式生成证书。该模式下,acme.sh 自己运行一个webserver, 临时监听在80 端口, 完成验证:
acme.sh --issue --standalone -d example.com -d www.example.com
如果服务器已经占用了80端口,可以通过--httpport参数使用80以外的端口:
acme.sh --issue --standalone -d example.com -d www.example.com --httpport 88
需要指出的是,standalone模式下,acme.sh会自己运行一个webserver,依赖的是socat,需要提前安装:
yum install socat
这是另一个standalone模式,使用了ssl,要求服务器的tcp 443端口空闲可用:
acme.sh --issue --alpn -d example.com -d www.example.com
可以通过--tlsport参数使用443以外的端口:
acme.sh --issue --alpn -d example.com -d www.example.com --tlsport 8443
webroot模式和standalone模式可以统称为http模式,即证书验证服务器通过http协议下载acme.sh客户端在域名指向的服务器上生成的验证文件来验证域名所有权。
在某些情况下,我们可能无法使用http模式,例如:
> 没有域名所指向的服务器的管理权限。
> 域名使用了CDN并设置了多个源站:由于验证文件只会在其中一个源站上生成,验证服务器将不能确保能够下载到验证文件。
此时,我们可以使用更加传统的DNS模式来生成证书,DNS模式要求用户在指定域名上设置指定的TXT记录值,已验证其对域名的所有权。
使用DNS模式生成证书需要3个步骤:
1). 指定dns模式,并声明已了解如何使用,生成TXT记录值。
acme.sh --issue --dns -d example.com -d www.example.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
使用DNS手动模式时,需通过--yes-I-know…参数声明已了解该模式的用法,否则,命令将会提示该模式的参考链接,不会实际执行。
执行命令后,将会获得以下输出:
Add the following txt record:
Domain:_acme-challenge.example.com
Txt value:9ihDbjYfTExAYeDs4DBUeuTo18KBzwvTEjUnSwd32-c
Add the following txt record:
Domain:_acme-challenge.www.example.com
Txt value:9ihDbjxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Please add those txt records to the domains. Waiting for the dns to take effect.
2). 配置DNS记录。
按照上一个步骤中的提示,到DNS服务提供商的控制台,为指定的域名添加指定的TXT记录,并等待一段时间,令DNS修改生效。
3). 生成证书。
回到acme.sh,使用--renew命令生成证书。
acme.sh --renew -d example.com -d www.example.com
需要指出的是,DNS手动模式中生成的域名TXT记录值是一次性的,因此,acme.sh无法在该模式下自动更新证书,当证书过期时,你必须手动重新生成证书。
DNS自动模式可以使用域名解析商提供的api自动为域名添加txt记录以完成域名所有权验证,不同于DNS手动模式,DNS自动模式支持自动更新证书。
acme.sh目前支持cloudflare,dnspod,aliyun,cloudxns,godaddy以及ovh等数十种解析商的自动集成。
以阿里云为例,DNS自动模式使用步骤如下:
1). 登录DNS提供商控制台,获取账户的api授权ID和密码。
阿里云地址:
https://ram.console.aliyun.com/manage/ak
获取AccessKeyId和AccessKeySecret。
2). 为acme.sh配置系统变量,存储api授权ID和密码。
export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"
3). 生成证书。
acme.sh --issue --dns dns_ali -d example.com -d www.example.com
该命令从系统变量中读取aliyun的api授权ID和密码,并通过dns_ali参数指定DNS提供商为阿里云。该命令将通过api自动为指定域名添加txt记录,并在验证完毕后自动移除txt记录。
aliyun的api授权ID和密码将被保存在.acme.sh的账户配置文件中,以供将来自动更新证书时使用,存储位置为:
~/.acme.sh/account.conf
更多DNS提供商的DNS自动模式使用方法请参考:
dnsapi · acmesh-official/acme.sh Wiki · GitHub
目前大部分的证书都是使用RSA非对称加密算法,但一些CA,例如letsencryption、zerossl等,已经支持颁发性能更加优良的ECC非对称加密算法证书。
通过—keylength参数申请ECC证书:
acme.sh --issue -w /home/webroot -d example.com -d example1.com --keylength ec-256
--keylength参数指定算法,ec-256表示256位的ecc非对称加密算法,可选的值有:
> ec-256 (prime256v1, "ECDSA P-256")
> ec-384 (secp384r1, "ECDSA P-384")
> ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)
泛域名证书的生成只适用于DNS验证的方式:
acme.sh --issue -d example.com -d '*.example.com' --dns dns_cf
如果想在当前证书剩余有效期在30天以上时重新生成证书,需要使用--force参数。
acme.sh --issue --nginx -d example.com -d www.example.com --force
默认情况下acme.sh会自动更新即将过期的证书,手动执行更新的方式如下:
acme.sh --renew -d example.com
如果是ecc证书:
acme.sh --renew -d example.com --ecc
acme.sh只会更新有效期不足30天的证书,如果想强制更新,则增加—force参数:
acme.sh --renew -d example.com --force --ecc
停止更新证书:
acme.sh --remove -d example.com [--ecc]
该命令执行之后,指定的证书不会再自动更新,但对应的证书文件并不会被从硬盘上删除。
当acme.sh生成证书后,不宜直接将web服务器的证书路径指向证书的生成路径:
~/.acme.sh/[domain]
因为该目录仅供acme.sh内部使用,有可能被修改。正确的做法是将证书文件拷贝至另外的目录。
可以直接通过拷贝命令直接拷贝证书文件,对应修改web服务器配置即可。
通过acme.sh的--install-cert命令来拷贝证书,并令web服务重新加载配置,需要注意的是,--install-cert命令并不会去修改web服务器的配置,因此,需要提前修改web服务器配置,将证书以及私钥路径指向部署路径,以nginx为例:
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 "service nginx force-reload"
--reloadcmd参数用于重新加载nginx配置。一个小提醒,这里用的是service nginx force-reload,不是service nginx reload。据测试,nginx的reload信号能够重新加载配置,但并不会重新加载证书,所以需要使用force-reload。nginx实际上没有force-reload这一信号,force-reload的实质为stop,然后start,即重启nginx。
示例:
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.fullchain.cer \
--reloadcmd "/usr/sbin/nginx -s stop && /usr/sbin/nginx"
在示例中,由于nginx没有注册为service,因此直接使用了nginx的停止和启动命令来重启nginx。
需要补充的是,这里指定的参数,包括证书拷贝的目的地,web服务器的重启命令等,都会被acme.sh自动记录下来,存储到对应证书的配置文件中。以证书example.com为例,存储路径为:
~/.acme.sh/example.com/example.com.conf
并且,在将来证书自动更新以后, --install-cert命令将被再次自动调用,以免去手动拷贝证书,以及重导web服务器配置的操作。
查看已经生成的证书:
acme.sh --list
手动更新:
acme.sh --upgrade
开启自动更新:
acme.sh --upgrade --auto-upgrade
关闭自动更新:
acme.sh --upgrade --auto-upgrade 0
如果运行acme.sh出错,可开启debug或者log。
查看debug:
acme.sh --issue ..... --debug
查看error:
acme.sh --issue ..... --debug 2
生成日志:
acme.sh --issue ..... --log
日志文件路径为:
~/.acme.sh/acme.sh.log