什么是acme.sh?为什么用acme.sh?
acme.sh 实现了 acme 协议, 可以从 letsencrypt 生成免费的证书
——摘自acme.sh Github项目介绍
简单来说,acme.sh可以帮助你无痛申请并部署免费的ssl证书
而相较于Let’s Encrypt在她官网推荐的Certbot客户端,acme.sh支持更多的DNS厂商,比方说DNSPod(使用腾讯云注册域名时默认的DNS厂商),在使用DNS验证方式验证时更省时省力
并且由于acme.sh 100%使用sh编写,因此你也并不需要做什么软件适配即可使用,也基本不会产生软件冲突(目前我使用经验)
并且,不管你是谁,你无需root权限即可安装acme.sh
(如果你使用Webroot mode申请证书,由于申请过程中需要将文件写入网站根目录,最好还是使用root来安装,当然,这是后话)
而且她有Docker部署方式 (什么Docker Fans)
(相信你一定会爱上她的)
目前acme.sh支持以下方式申请证书:
- 网站根目录文件验证 (需要用户拥有网站根目录写权限)
- 独立验证 (需要安装socat服务)
- tls alpn独立验证 (需要安装socat服务)
- Apache服务验证 (可替代网站根目录文件验证)
- Nginx服务验证 (可替代网站根目录文件验证)
- DNS验证 (需要申请DNS API或手动添加DNS解析)
- DNS CNAME验证(请查阅官方文档)
- 服务配置模式验证(请查阅官方文档)
本文参考acme.sh官方文档和笔者个人经验书写
如果你对本文有任何问题,欢迎在下方评论区友好讨论
少说多做开始动手
具体的操作文档你可以点击此处查看
如果你需要有关Docker部署方面的教程,请在左边菜单选择 给Docker Fans的一点小参考
章节
⚠️ 注意!本文仅介绍基本的用法,详细用法请前往acme.sh查看
安装acme.sh
仅需要一条命令即可安装acme.sh
但请注意,你需要将my@example.com
这一段替换为你自己的邮箱
curl https://get.acme.sh | sh -s email=my@example.com
你也可以先克隆GIT仓库来安装
git clone --depth 1 https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m my@example.com
在国内 (较差) 网络环境下,你可以使用此条命令安装
git clone --depth 1 https://gitee.com/neilpang/acme.sh.git
cd acme.sh
./acme.sh --install -m my@example.com
由于自动更新证书需要使用crond服务来运行,因此你需要先安装crond服务再安装acme.sh
当然你也可以添加 --nocron
参数来在无crond服务下安装,只不过证书自动更新将无法使用
curl https://get.acme.sh | sh -s email=example@example.com --nocron
安装后的tips
在安装过程中,acme.sh自动写入了你的.bashrc
文件,这让你可以像使用命令一样调用她
也就是说,你不需要在acme.sh安装目录下就可以调用她
由于acme.sh默认CA为ZeroSSL,而在我本人实际使用中发现ZeroSSL似乎不太喜欢国内的网络环境,而Let’s Encrypt却完全能够承受
那,我们先换个CA再说
acme.sh --set-default-ca --server letsenctypt
letsenctypt字段可以更换为acme.sh默认支持的CA或支持acme协议的链接
点击查看acme.sh默认支持的CA
由于acme.sh目前经常更新,因此建议在使用之前将其自动更新打开并检查一遍更新
acme.sh --upgrade --auto-upgrade
申请证书吧!
但是,在申请之前,我还是希望你能够看看这些内容:
- 接下来的内容中,我将用
example.com
作为申请域名,你需要将此域名更换为你自己的域名 - 在申请过程中如果出现任何错误,你可以添加
—-debug
参数来debug(废话)
本文不会研究如何debug - 你可以申请多种类型的证书,仅需在申请命令后方添加参数
—-keylength (2048|3072|4096|8192|ec-256|ec-384|ec-521)
- 你可以同时为多个域名申请证书。当你同时为多个域名申请证书时,一般而言,你的申请命令中第一个出现的域名即为证书的主域名。如果你不确定证书的主域名是哪一个,可以使用
acme.sh —-list
来查看 - 当你同时为多个域名申请证书时,如果你仅指定一种验证方式,那么所有的网址都将使用这一种的方式进行验证。当然,你也可以为不同的域名指定不同的验证方式,其类似于这样的格式:
acme.sh --issue
-d aa.com -w /home/wwwroot/aa.com
-d bb.com --dns dns_cf
-d cc.com --apache
-d dd.com -w /home/wwwroot/dd.com
那么现在,我们开干吧
DNS验证
DNS验证分为自动DNS验证(需要DNS厂商提供API)和手动DNS验证,其中手动DNS验证方式不支持自动续签
仅DNS验证支持申请泛域名证书
(有可能DNS CNAME验证也可以?我到时候试试)
自动DNS验证
在此之前,请你先打开这个网页:acme.sh支持的自动DNS验证厂商列表
现在,你需要找到你的域名当前使用的DNS厂商,这里选择常用的Cloudflare
和DNSPod
举例子
(部分厂商有特殊的自动验证的要求,这就是为什么看文档总比看别人写的文章好的原因)
Cloudflare
Cloudflare有两种API密钥,一种是区域密钥,一种是全局密钥
点击此处前往API获取页面
使用全局密钥的话,当然会更加简便,但也会增加安全风险
全局密钥需要你的Cloudflare全局密钥
和Cloudflare登录邮箱
,而区域密钥需要你的用户Token
和区域ID
要查看你的全局密钥,请在你的API页面的Global API Key
这一行点击查看按钮获取你的全局密钥
要使用区域密钥,请点击创建令牌
-> 编辑区域 DNS
-> 区域资源下选择你的域名
-> 创建令牌
来获取你的用户Token,你可以在你的网站概述
下找到你的域名区域ID
使用全局密钥
export CF_Key="Your Cloudflare Global API Key"
export CF_Email="Your Cloudflare Login Email"
使用区域密钥
export CF_Zone_ID="Your Cloudflare Website Zone ID"
export CF_Token="Your Cloudflare User API Token"
最后我们来申请证书吧!
acme.sh --issue --dns dns_cf -d example.com -d *.example.com
DNSPod
甚至DNSPod官方都有 acme.sh on DNSPod 的教程
如果一切正常,那么你的证书将会被自动下载
手动DNS验证
acme.sh --issue --dns -d example.com
--yes-I-know-dns-manual-mode-enough-go-ahead-please
你会得到类似这样的回应:
[Sun Feb 11 18:52:50 CST 2024] Add the following TXT record:
[Sun Feb 11 18:52:50 CST 2024] Domain: "_acme-challenge.example.com"
[Sun Feb 11 18:52:50 CST 2024] TXT value: "xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
这时请你添加一条DNS解析:
- 解析类型为
TXT
- 名称为上方输出中
Domain
的内容,在本例中为_acme-challenge.example.com
⚠ 注意,一般情况下在添加TXT解析时dns厂商会自动帮你添加example.com
字段 - 内容为上方输出中
TXT value
的内容,在本例中为xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
当添加完DNS解析之后,请你使用此条命令继续申请证书
acme.sh --issue --renew -d example.com
--yes-I-know-dns-manual-mode-enough-go-ahead-please
如果一切正常,那么你的证书将会被自动下载
网站根目录文件验证
作为最朴素(也是最简单)的验证方式,你只需要指定你的域名绑定的网站根目录即可完成验证
本例中以/home/wwwroot/example.com
作为网站根目录
acme.sh --issue -d example.com -w /home/wwwroot/example.com
如果一切正常,那么你的证书将会被自动下载
独立验证
独立验证也有两种方式,但其实都差不多
如果你的服务器并没有运行网站服务,此时用此种验证方式会更为简单
适用于没有任何服务绑定了80端口或者443端口的服务器类型
由于此种方式依赖于socat服务,我们需要先安装socat服务
#For RHEL Series
sudo dnf install -y socat
#For Debian Series
sudo apt install -y socat
此种验证方式需要监听80/443端口,因此你需要使用root权限来进行验证
使用80端口
acme.sh --issue --standalone -d example.com -d www.example.com -d cp.example.com
使用443端口
acme.sh --issue --alpn -d example.com -d www.example.com -d cp.example.com
如果一切正常,那么你的证书将会被自动下载
网站服务验证
网站服务验证,顾名思义,你需要先安装nginx或者Apache httpd这二者其中一个服务方可使用。
她会更改你的网站服务配置,但请放心,证书签发完成之后都会给你改回来
其实在实际上,根据我的测试,
网站服务验证
只是服务配置模式验证
的自动化而已
其实也是网站根目录文件验证
的另外一种方式
Nginx服务验证
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
Apache服务验证
acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
如果一切正常,那么你的证书将会被自动下载
安装证书吧!
由于acme.sh并不会自动帮我们更改网站服务(如nginx和Apache httpd)的配置文件,因此我们需要手动告诉acme.sh要将签发下来的证书放置在哪里,并执行什么命令使网站服务重载或重启
在此用以nginx为网站服务的服务器为例:
- 我们安装的证书是以
example.com
为主域名的证书 - 将公钥文件写入
/etc/nginx/conf.d/ssl/server.crt
文件 - 将私钥文件写入
/etc/nginx/conf.d/ssl/server.key
文件 - 将CA证书写入
/etc/nginx/conf.d/ssl/ca.crt
文件 - 将FullChain文件写入
/etc/nginx/conf.d/ssl/fullchain.pem
文件 - 命令nginx服务器重新加载配置文件的命令为
nginx -s reload
那么,我们的命令应该是这个样子
acme.sh --install-cert -d example.com
--cert-file /etc/nginx/conf.d/ssl/server.crt
--key-file /etc/nginx/conf.d/ssl/server.key
--ca-file /etc/nginx/conf.d/ssl/ca.crt
--fullchain-file /etc/nginx/conf.d/ssl/fullchain.pem
--reloadcmd "nginx -s reload"
在你执行此命令过后,如果一切正常,你将在你指定的位置发现你的证书(他们很乖的)
如果你同时指定了 —-reloadcmd
,acme.sh会尝试运行指定的重载命令并将命令运行时的输出打印出来
如果在acme.sh运行重载命令时报错也不要担心,你只需要调整好你的 —-reloadcmd
并且将上面的安装证书命令在运行一次,此时 —-reloadcmd
将会被覆盖为最新的指定命令
⚠️注意:光申请证书而不修改任何配置文件是不会有任何效果的,你需要自己修改网站服务的配置文件来将ssl证书部署到线上
请点击此处查看ssl证书的部署教程
这些就是全部内容了!感谢你阅读这篇文章
给Docker Fans的一点小参考
好好好,现在我知道你要用Docker了
你可以参考acme.sh官方的Docker文档
我不太喜欢他的文档,因为要挂载docker.sock
文件,这可能对安全性造成影响
(Docker = Root)
并且如果你要同时给多个容器部署(好像可以?)会有点麻烦
因此,这是我的解决方案,支持在install-cert
之后在Docker宿主机上执行你希望的命令
按照我的懒人习惯,可能会在之后写一个自动部署脚本,期待吧
部署acme-reloader
这里有好几个文件需要你下载并解压
wget https://ftp.esaps.net/dockersh/acme.sh/acme-reloader.tar.gz
tar xzvf acme-reloader.tar.gz
解压下来之后的文件目录长这样
acme-reloader
|- ssl/
| |-
|- config/
| |-
|- acme-reloader/
| |-
|- acme-reloader-host.service
|- acme-reloader-host.sh
|- acme-reloader.sh
|- docker-compose.yml
正常来说,我们只需要进入acme-reloader
目录并运行docker compose up -d
即可启动acme.sh的容器
怎样在不挂载docker.sock的情况下重载Docker容器
改个文件先
如果你使用网站根目录验证的话,你需要挂载你的网站目录到容器里面
请找到我们的acme-reloader-host.sh
文件并找到这个片段并按照注释修改文件(已将注释翻译)
function restart_command() {
#请在这里放下你在证书申请完成之后需要在docker宿主机上执行的命令
#请类似于这样的格式书写:restart_with "需要执行的命令",一行一条
#这样才可以在本目录下acme-reloader.log查找到命令执行异常时的日志
restart_with "YOUR_OWN_SH_COMMAND"
#输入完成!请不要更改其他文段并享受你的自动化过程吧 :)
echo "Complete" >> ./socket/acme-reloader.sock
}
找到我们的acme-reloader-host.service
文件并作出以下更改
- 请将
/path/to/acme-reloader-host.sh_directory
替换为acme-reloader目录
的绝对路径 - 请将
/path/acme-reloader-host.sh
替换为到acme-reloader-host.sh
的绝对路径
然后,把这个文件复制到/usr/lib/systemd/system/
目录里面
(请注意,如果你的Linux发行版过早,可能使用的是init.d而非systemd,这个时候我相信你可以自己写一个服务脚本的)(确信)
(算了不那么欠扁到时候我再写一个吧)
acme-reloader-host,启动!
执行命令来让systemd操控我们的acme-reloader
吧
systemctl daemon-reload #重载配置文件,必须执行一次,否则可能提示找不到acme-reloader-host.service
systemctl start acme-reloader-host.service #启动acme-reloader-host
systemctl stop acme-reloader-host.service #关闭acme-reloader-host
systemctl restart acme-reloader-host.service #重启acme-reloader-host
systemctl status acme-reloader-host.service #查看acme-reloader-host运行状态
在接下来的操纵前,你需要先启动acme-reloader-host
服务,否则你可能在acme.sh执行重启命令时收到错误信息
还需要一点操作
将acme-reloader.sh
文件复制到acme.sh
容器的根目录(注意替换为你自己的容器名称,如果使用了我的docker-compose.yml可以不用更改)
docker cp ./acme-reloader.sh acme.sh:/
然后,像本文前面内容一样申请证书吧~
sudo docker exec -it acme.sh acme.sh
由于我们是在Docker容器里面运行,所以要用这种繁琐的方式来替换前文的爽快acme.sh命令
如果你怕麻烦,你可以执行这条命令来简便一点
alias acme.sh="docker exec -it acme.sh acme.sh"
你也可以直接进入acme.sh容器来操作
docker exec -it acme.sh ash
接下来我会使用acme.sh命令直接演示
因为我们是直接运行了Docker容器,所以我们需要先在CA那边注册一个账号
acme.sh --register-account --server letsencrypt -m myemail@example.com
并且更换acme.sh的默认CA
acme.sh --set-default-ca --server letsencrypt
然后就可以按照上面的内容一样申请证书喽
注意:如果你使用自动DNS验证申请的话,最好还是直接进入容器里面先申请一次,让acme.sh先保存你的API密匙
最后一点点了!
是的,还差安装证书
acme.sh --install-cert -d example.com \
--cert-file /etc/nginx/conf.d/ssl/server.crt \
--key-file /etc/nginx/conf.d/ssl/server.key \
--ca-file /etc/nginx/conf.d/ssl/ca.crt \
--fullchain-file /etc/nginx/conf.d/ssl/fullchain.pem \
--reloadcmd "sh /acme-reloader.sh"
我默认在docker-compose.yml
帮你挂载了/ssl
目录,这个目录docker-compose.yml的同级目录下
--reloadcmd
必须改为sh /acme-reloader.sh
,这样子我们才可以通知宿主机来执行重载命令
如果你没有在宿主机上启动acme-reloader-host服务,将会提示
Host error: Unable to connect to host.
此时需要你先启动acme-reloader-host服务再重新安装证书
还有,acme-reloader-host服务的日志在acme-reloader-host.sh同级目录下,如果重载失败了你可以查看是哪条命令出错了喵
完成~!享受你的证书自动化吧!
(多嘴一句,你需要自己修改网站服务配置文件来部署,具体看这里)
发表回复