esap~!
esap~!

用acme.sh来为你的站点申请免费的ssl证书吧!

用acme.sh来为你的站点申请免费的ssl证书吧!

什么是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
但请注意,你需要将[email protected]这一段替换为你自己的邮箱

curl https://get.acme.sh | sh -s [email protected]

你也可以先克隆GIT仓库来安装

git clone --depth 1 https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m [email protected]

在国内 (较差) 网络环境下,你可以使用此条命令安装

git clone --depth 1 https://gitee.com/neilpang/acme.sh.git
cd acme.sh
./acme.sh --install -m [email protected]

由于自动更新证书需要使用crond服务来运行,因此你需要先安装crond服务再安装acme.sh
当然你也可以添加 --nocron 参数来在无crond服务下安装,只不过证书自动更新将无法使用

curl https://get.acme.sh | sh -s [email protected] --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厂商,这里选择常用的CloudflareDNSPod举例子
(部分厂商有特殊的自动验证的要求,这就是为什么看文档总比看别人写的文章好的原因)

Cloudflare

Cloudflare有两种API密钥,一种是区域密钥,一种是全局密钥
点击此处前往API获取页面
使用全局密钥的话,当然会更加简便,但也会增加安全风险
全局密钥需要你的Cloudflare全局密钥Cloudflare登录邮箱,而区域密钥需要你的用户Token区域ID

CloudFlare API页面示例

CloudFlare API页面示例

要查看你的全局密钥,请在你的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  [email protected]

并且更换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同级目录下,如果重载失败了你可以查看是哪条命令出错了喵

完成~!享受你的证书自动化吧!
(多嘴一句,你需要自己修改网站服务配置文件来部署,具体看这里

赞赏

AptS:1547

文章作者

这里是AptS:1547!希望能给你带来快乐!

发表回复

textsms
account_circle
email

esap~!

用acme.sh来为你的站点申请免费的ssl证书吧!
用acme.sh申请免费的SSL证书吧!完全自动且部署后自动续签!
扫描二维码继续阅读
2024-02-24