看到“ALLinSSL 部署指南”这个标题,圈内人应该能立刻反应过来,这是又遇到了一个想把 SSL 证书生命周期管理一揽子打包的自托管项目。我个人的理解很简单:它把所有跟证书打交道的事——申请、续期、推送部署、到期提醒——收进同一个应用里,再用一份配置文件把流程串起来。如果你手里管着好几个域名,分布在不同的服务器上,或者你正在为团队内部几十张证书的续期发愁,这份指南就是给你写的。
先说句大实话,我吐槽过无数次的老方案:一台机器一个站点,手动上去跑一次命令拿证书,再手动放证书、改配置、重启服务。域名少的时候没问题,一旦超过五六个,这种操作方式就会变成定时炸弹。ALLinSSL 要解决的,就是把“证书申请了几次”“哪些证书快过期了”“到底部署到哪台机器上了”这些问题,全部收口到一个可复用的配置和一套自动任务里。下面我从部署前的准备工作、两条部署路径、核心配置到排障,完整走一遍。
1. 认识ALLinSSL:它到底帮你干了什么
1.1 从需求倒推功能
应该先想清楚一个问题:你为什么会需要这个东西?我见过不少团队,证书管理还停留在“手工台账”阶段,用 Excel 记录域名、到期时间、部署位置。表面看没什么问题,可一到续期高峰,漏一张、错一张的现象就特别容易发生。任何一个证书过期,带来的不是服务不可用,就是用户看到安全警告,严重一点直接丢业务。
ALLinSSL 这类工具的存在,本质上就是把运维里“周期性、重复性、易错性”最高的三件事自动化:
- 证书申请:通过 ACME 协议向公共 CA 申请证书,自动完成域名验证。
- 证书续期:检测证书剩余有效期,在安全窗口内自动更新。
- 证书部署:把新的证书文件推到本机 Web 服务、远程服务器,或者通过回调通知其他系统。
这三点串成一条链路之后,运维要做的只剩两件事:第一,把要管理的域名和验证方式写进配置;第二,在证书真的出问题时看日志和告警。剩下的时间该干嘛干嘛。
1.2 和现用方案对比
也许有人会问:我直接用 certbot 或者 acme.sh 不就行了?说实话,这两类工具在“申请证书”这个环节确实做得很好,但问题在于它们的边界就停在那里。证书拿到之后,部署到本机 Nginx 要靠脚本,推送远程服务器要靠写 rsync/scp,到期提醒往往没人做。所有的“最后一公里”工作还是得靠人。
拿一张表格对比就很直观:
| 能力维度 | 手动 certbot/acme.sh | 自写脚本+定时任务 | ALLinSSL |
|---|---|---|---|
| ACME 证书申请 | 支持 | 支持 | 支持 |
| 多域名集中管理 | 分散在各机器 | 需要自己汇总 | 配置文件统一管理 |
| 自动续期 | 自带但分散 | 依赖 cron 正确性 | 内置调度器 |
| 部署推送 | 无 | 自己写部署脚本 | 内置本地/SSH/Webhook |
| 到期监控 | 无 | 自己写检查脚本 | 内置通知 |
| 恢复重建 | 重新折腾 | 脚本容易失传 | 配置即备份 |
所以我的判断是:如果你的域名数量小于等于 3,而且都在这台机器上,那直接用现成的 ACME 客户端完全足够。一旦你手上的证书超过 10 张,分布到多台机器,或者你不想过年时候被老板电话叫起来换证书,ALLinSSL 这类整合型工具就派上用场了。
1.3 适用人群与使用场景
根据实际接触到的案例,这类部署实际跑得最顺的是这几类用户:
- 个人站长:手里域名不少,有主站、有子域、还有为某个活动临时开的站点,统一收口管理。
- 小团队运维:两三个人管全公司业务,证书散落各处,希望有一个独立服务把证书生命周期管起来。
- 集中式网关/反代场景:证书都集中部署在网关、负载均衡器、Kubernetes Ingress 上,源站不直接对外。
如果你的情况在上面三类里,那接着往下看部署步骤,完全可以照着实操。
2. 部署前的准备工作:环境、端口和目录规划
2.1 服务器评估与网络要求
不要一上来就搞一台高配机器。ALLinSSL 本质是个轻量级管理服务,哪怕你给它管一百张证书,它的资源消耗都很低,1 核 1G 内存的机器绰绰有余。真正要关心的是网络连通性,这决定了 ACME 验证能不能成功。
需要搞清楚的关键点:
- 这台机器必须有公网 IP,或者至少能通过端口映射和网关被外部访问到。
- HTTP-01 验证要求外部能访问 80 端口;你要部署证书的站点如果用了 443,那 443 也需要能够访问。
- 出方向要能访问 ACME 目录接口,也就是证书签发服务商的 API 地址。如果机器在防火墙后面,需要放开这一步的请求。
- 系统时间必须准确。ACME 整个流程依赖时间校验,如果时间差超过五分钟,签发必然失败。部署前先跑一遍
date -R看看时间对不对,不对就配置 NTP 同步。
这块我踩过坑。之前有一台内网机器,我图省事直接从外网 server 上把证书 scp 过去,后来统一管理想改成这台机器自己签,结果发现它连 CA 的出站 HTTPS 都被防火墙拦了,调了半天才发现是网络策略问题。所以先说清楚,ALLinSSL 这台管理节点需要有出外网的能力。
2.2 域名解析与 TTL 设置
部署之前,把你要管理的域名都解析到这台机器上。怎么解析取决于你后边用哪种验证方式:
- HTTP-01:域名解析到本机公网 IP。
- DNS-01:需要你的域名托管在支持 API 操作的 DNS 服务商那里,解析记录可以由程序自动创建和删除。
无论哪种方式,建议在做 ACME 验证之前,先把域名的 TTL 调低,比如 600 秒,避免验证失败后反复等缓存过期。用dig +short example.com确认解析记录已经生效,再往下走。
这里有个小提醒:如果你打算后面只做 DNS-01 验证,其实这台机器不要求能被外部直接访问,只要它能访问 DNS 服务商的 API 就行。但为了保留 HTTP-01 的灵活性,建议还是开放公网入口。
2.3 数据目录与系统环境规划
目录规划这个环节很多人会忽略,但它直接影响后续的迁移和备份。我推荐按照下面的结构来建,逻辑清楚,权限也容易控制:
mkdir -p /opt/allinssl/{config,certs,logs,data}- config:存放主配置文件,包括 CA 账号、域名列表、通知配置。
- certs:证书输出目录,按域名区分子目录。
- logs:运行日志和操作审计日志。
- data:程序内部数据,比如证书状态缓存、数据库文件。
不管用 Docker 还是 systemd 部署,这四条目录都会挂载进去。后续要备份,直接打包这一个目录就行,省得到处找文件。
系统依赖方面,如果走 Docker 路径,需要装好 Docker 和 Docker Compose 插件;如果走 systemd 路径,需要一个可执行二进制文件和一个文本配置文件,基本零依赖。
提示:无论用哪种方式,都别用 root 直接跑业务进程。可以单独建一个系统用户,比如
allinssl,再把上述目录的属主改成这个用户。
2.4 防火墙与系统安全项
准备工作的最后一步是开放端口。如果开了系统防火墙,记得放行:
sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 8080/tcp # 按需,这是 Web 管理/API 端口端口策略上我建议遵循最小化原则:80 和 443 是给 ACME 验证和对外服务用的,8080 或者你想绑定的管理端口,不要暴露到公网。如果必须远程管理,走 SSH 隧道访问。
3. 两种部署路径的实操过程
3.1 Docker Compose 部署路径
Docker Compose 是多数人选择的方式,因为环境隔离、升级方便、回滚容易。进入规划好的目录,先创建docker-compose.yml:
services: allinssl: image: example/allinssl:latest container_name: allinssl restart: unless-stopped network_mode: host volumes: - /opt/allinssl/config:/app/config - /opt/allinssl/certs:/app/certs - /opt/allinssl/logs:/app/logs - /opt/allinssl/data:/app/data environment: TZ: Asia/Shanghai关于network_mode: host这个选择,我多说一句。用 bridge 模式也行,但 SSL 证书部署经常需要容器里写的证书被宿主机 Nginx 直接读取,而 ACME 验证又需要访问宿主机端口,用 host 网络可以避免端口映射的绕来绕去。如果你不希望容器和宿主机共享网络,那就需要把端口映射写清楚,比如:
ports: - "80:80" - "443:443" - "8080:8080"我个人更推荐 host 模式,因为后续让容器直接操作宿主机上的 Nginx 配置、证书目录时会方便得多,不需要额外维护一套端口映射关系。
写好配置后启动:
cd /opt/allinssl docker compose up -d启动后先看日志,确认进程没有异常退出:
docker compose logs -f --tail=100看到日志输出里出现了健康检查通过、服务监听正常之类的信息,基本就成功了。
3.2 systemd 裸机部署路径
如果你不喜欢容器,或者目标机器上本来就没有 Docker 环境,用 systemd 管理二进制文件也很简单。把编译好的二进制文件放到/usr/local/bin/allinssl,配置文件放在/opt/allinssl/config/config.yaml,然后创建一个服务单元。
编辑/etc/systemd/system/allinssl.service:
[Unit] Description=ALLinSSL Certificate Management Service After=network-online.target Wants=network-online.target [Service] Type=simple User=allinssl Group=allinssl WorkingDirectory=/opt/allinssl ExecStart=/usr/local/bin/allinssl --config /opt/allinssl/config/config.yaml Restart=always RestartSec=5 LimitNOFILE=65535 [Install] WantedBy=multi-user.target启动服务:
sudo systemctl daemon-reload sudo systemctl enable --now allinssl sudo systemctl status allinssl这里有个细节:User=allinssl需要你先创建好这个用户,而且/opt/allinssl/certs目录必须让这个用户有写权限,否则申请证书时没法写文件,续期也会失败。别问我怎么知道的,这种权限问题通常在第一次证书签发时才暴露出来。
3.3 首次启动后的配置初始化
服务跑起来之后,先别急着往配置文件里堆域名,先确认服务健康。可以用内置的 CLI 工具或者 API 来检查状态,常见的操作是:
allinssl-cli status或者直接看 API 返回:
curl -s http://127.0.0.1:8080/api/health接下来你要做的第一件事情是注册 ACME 账号。大多数公共 CA 用邮箱即可注册账号,ALLinSSL 会在第一次签发时自动完成这一步,但你最好在配置里先写好邮箱,避免后面漏掉续期通知。这一步相当于先给整个系统建立“身份”,之后所有的申请记录都和这个账号绑定。
4. 核心配置解析:验证方式与证书申请参数
4.1 一份可以直接抄的配置文件
整个部署流程的精华都在配置文件里。我先给出一份带完整注释的config.yaml,覆盖 HTTP-01 和 DNS-01 两种场景:
ca: account_email: admin@example.com acme_directory: https://acme.example-ca.com/directory scheduler: check_interval: 24h renew_before: 30d certificates: - name: main-site domain: example.com san: - www.example.com challenge: http-01 deploy_to: - type: local webroot: /etc/nginx/ssl reload_service: nginx - name: api-gateway domain: "*.api.example.com" challenge: dns-01 dns_credential_id: cloud_dns_prod deploy_to: - type: ssh host: 10.0.0.5 user: deploy path: /etc/nginx/ssl reload: true notifier: - type: webhook url: https://ops.example.com/hooks/cert secret: change-me-to-a-long-random-string这里面的字段看着多,但核心逻辑很简单:每条certificates记录定义了一个“证书申请任务”,包括域名、验证方式、证书下发之后要干什么。
4.2 验证方式:HTTP-01 还是 DNS-01
这是整个配置里最需要动脑子的地方。两者各有适用场景,选择错误会让整个链路变得不稳定。
| 对比维度 | HTTP-01 | DNS-01 |
|---|---|---|
| 验证原理 | CA 访问http://域名/.well-known/acme-challenge/xxx | CA 查询域名的_acme-challengeTXT 记录 |
| 适用证书 | 单域名、多域名 SAN 证书 | 泛域名证书、离线签发 |
| 端口依赖 | 必须开放 80 端口 | 无端口要求 |
| 自动化程度 | 自动创建临时文件名即可 | 需要 DNS 服务商 API 凭证 |
| 安全性 | 需要 Web 服务配合 | 凭证泄露风险需提防 |
| 失败率 | 受网络和 Web 服务配置影响 | 受 DNS 生效速度影响 |
我的经验是:能上 DNS-01 就优先上 DNS-01。理由很简单,泛域名证书必须用 DNS-01,而且它不依赖 80 端口是否被其他服务占用。你只要把 DNS 服务商的 API 密钥配置好,后面基本一劳永逸。HTTP-01 则适合那些域名没有 API 管理能力的场景,比如 DNS 托管在比较封闭的平台上。
但 DNS-01 有一个坑:DNS 解析生效有延迟。如果系统提示验证失败,先去查一下 TXT 记录是否已经能查到:
dig +short TXT _acme-challenge.example.com如果看不到记录,说明要么凭证权限不對,要么服务商 API 返回成功但实际生效还需要等待。
4.3 部署目标和通知配置
证书签下来只是第一步,部署到目标位置才是价值所在。配置文件里的deploy_to支持几种常见模式:
- local:写到本机目录,适合“管理节点也是 Web 节点”的场景。
- ssh:推到远程服务器,适合证书集中签发、分发到各业务节点的场景。
- webhook:把证书内容 POST 到某个接口,适合对接 Kubernetes Ingress Controller 或者云负载均衡。
SSH 推送这里要注意:ALLinSSL 会用指定用户去连接目标机器,所以要先配置好免密登录。命令大致是:
ssh-keygen -t ed25519 -C "allinssl-deploy" ssh-copy-id deploy@10.0.0.5然后把私钥路径写进配置文件对应位置。免密登录配置完成后,先手动ssh deploy@10.0.0.5连接一次,确认能通再交给工具,不然第一次推送失败会非常被动。
通知配置一般建议至少配一个 Webhook 或者邮箱。ALLinSSL 会在证书到期前、续期成功、推送失败、续期失败这几个事件点上发通知。Webhook 建议加一个签名机制,比如用secret对请求体做 HMAC 签名,接收方验证签名后再处理,防止伪造请求。
4.4 密钥和权限管理
配置里涉及两类敏感信息:DNS 服务商 API 密钥和 SSH 私钥。它们如果被任意用户读取,等于把整个证书体系的控制权交出去。所以部署完成后必须收紧权限:
chown -R allinssl:allinssl /opt/allinssl chmod 600 /opt/allinssl/config/config.yaml chmod 700 /opt/allinssl/data chmod 600 /opt/allinssl/certs/*/privkey.pem如果支持数据加密,建议开启密钥加密存储功能。也就是说,敏感字段在写入磁盘前先用主密钥加密,启动时再解密。这样即使配置文件被拖走,攻击者拿到的也只是密文。虽然会带来一些操作上的麻烦,但对证书管理系统来说,这种投入是值得的。
5. 自动续期和证书推送的运行机制
5.1 证书有效期与续期窗口的计算
公共 CA 签发的证书默认有效期通常在 90 天左右。如果你在证书刚签出来就马上去续期,ACME 服务端可能直接忽略请求,而且频繁申请还可能触发速率限制。所以续期窗口的选择很重要。
我在配置里写的是renew_before: 30d,意思是证书剩余有效期小于 30 天时触发续期。这样算下来,一张 90 天证书大约在签发后第 60 天自动发起续期,既留出足够的操作缓冲,又不会过早打扰 CA。
如果你管理的是那种有效期一年的证书,可以把renew_before改成 30 天或者 45 天,逻辑是一样的:只要剩余天数小于这个阈值,系统就认为该续期了。需要注意的是,这个数值不能设得太激进,比如离到期还有 80 天就去续,很多 CA 会返回 429 错误。
5.2 调度器与触发逻辑
ALLinSSL 的调度器逻辑并不复杂,它做的就是周期扫描:
- 读取配置中的证书列表。
- 检查每张证书的当前剩余有效期。
- 如果剩余天数小于
renew_before,进入待续期队列。 - 执行续期操作并校验证书有效性。
- 续期成功后触发后续部署任务。
调度周期我一般设成24h,也就是每天检查一次。不用太频繁,因为证书续期颗粒度本来就是按天计算的,设成每小时反而是浪费资源,还容易在 API 日志里制造噪音。
有个细节值得留意:调度器判断续期依据是“现有证书文件的剩余天数”,所以如果证书文件还没生成过,它会直接走初始签发流程。这保证了新加域名后,即使你不在创建任务时手动触发一次,系统也会在下一次检查时自动把证书签出来。
5.3 推送执行的关键细节
续期成功后,推送过程比续期更容易出问题。以本地 Nginx 为例,推送不是简单地把文件复制过去就完了,还涉及重载服务。如果证书和配置不匹配,Nginx 可能直接拒绝启动或重载失败,造成更大故障。
所以推送执行前,系统会做一次校验:
- 私钥能否和证书匹配。
- 证书是否已经过期。
- 证书链是否完整。
校验通过后才执行写入和重载。在配置里,本地推送可以指定reload_service: nginx,实际操作时会执行类似这样的命令:
nginx -t && systemctl reload nginxnginx -t这一步是为了在真正重载前确认配置没有语法错误,避免“证书更新了,服务挂了”的情况。
SSH 推送逻辑也差不多,而且因为多了网络交互,失败率更高。建议在 SSH 推送配置里确保目标路径存在,并且deploy用户对该路径有写权限。目标机器上最好也做一次nginx -t再重载,而不是直接重载。
5.4 失败重试与日志审计
任何自动任务都会失败,关键是有没有兜底。推荐配置里把重试次数设置为 3 次,重试间隔采用指数退避,比如 1 分钟、5 分钟、15 分钟。连续三次失败后,系统应该立刻发告警通知,而不是留在队列里默默重试一整天。
平时多关注日志,因为日志里能看到每个任务的全过程。遇到问题先看日志,基本能定位 80% 的故障。尤其是看到failed to reload nginx或者no route to host这类关键字,问题方向就明确了。
6. 高频问题排查表与避坑心得
6.1 验证失败类问题
ACME 验证失败是最常见、也最让人头疼的。我遇到过的主要有这么几类:
- 域名解析未生效:解析记录刚加完就去申请,TTL 没过去,CA 服务器查询不到正确记录。
- 端口不通:服务器防火墙没放行 80 端口,或者云安全组里没配入方向规则,仔细检查。
- DNS API 凭证权限不对:API 密钥没有创建/删除 TXT 记录的权限,验证记录写不进去。
- 速率限制触发:同一个域名在 7 天内申请新证书超过 5 次,被 CA 暂时锁定。
排查时按顺序做三件事:
dig +short example.com dig +short _acme-challenge.example.com TXT curl -I http://example.com/.well-known/acme-challenge/test第一个看 A 记录,第二个看 TTL 是否生效,第三个确认 80 端口和 Web 服务是否正常。
注意:别用同一域名反复测试签发,ACME 的速率限制是按“新证书签发次数”计算的,频繁测试会把自己锁死。要测试就先用一个不重要的域名,或者直接看日志确认逻辑没问题再上正式域名。
6.2 权限类问题
很多由证书文件引发的服务不可用,本质是权限不对。常见症状是 Web 服务提示Permission denied,或者证书路径不存在。
检查顺序:
ls -l /etc/nginx/ssl/ ls -l /etc/nginx/ssl/privkey.pem正确的权限应该是证书目录可读可执行,私钥文件 600,其他人不可读。如果 Nginx 不是 root 运行的,要确保 Nginx 进程用户能读取证书和私钥文件。之前有次我推送完证书后,发现 Nginx 还是报错,最后排查出来是证书文件属主是 root,而 Nginx worker 进程用户是 www-data,加一句chown :www-data就解决了。
SSH 推送失败也多是权限问题。服务端私钥权限太宽(比如 644),SSH 会直接拒绝使用;目标机器的~/.ssh/authorized_keys内容不对,或者目标目录属主不对,也会失败。逐一排查,别猜。
6.3 续期与时钟问题
证书续期依赖精准的时间判断。如果你发现系统明明到了续期窗口却不触发,大概率是系统时间和实际时间偏差太大。还有个隐蔽问题:Docker 容器默认时区是 UTC,如果你在管理面板里看到的到期时间和实际差 8 小时,不一定是 bug,只需要你在启动容器时设置TZ=Asia/Shanghai就好。
另外,续期失败后不要立刻手动强制续期。先确认失败原因,如果是因为 CA 拒绝或者网络问题,等下一次调度即可,硬试反而容易触发速率限制。
6.4 高频问题排查速查表
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 证书签发失败,提示 DNS 无记录 | 域名解析未生效或 TTL 未过 | 等 TTL,用dig验证 |
| 证书签发失败,提示连接超时 | 80 或 443 端口不通,出站 API 被拦 | 检查防火墙和安全组 |
| 证书续期不触发 | 剩余有效期仍大于阈值 | 确认系统时间和时区 |
| 推送后 Nginx 启动失败 | 证书和配置不匹配 | 先跑nginx -t |
| Nginx 日志显示 Permission denied | 证书文件权限不对 | chmod 600 私钥,chown 给运行用户 |
| SSH 推送失败 | 免密登录没配好或私钥权限太宽 | 用ssh-copy-id重新配置,chmod 600 |
| 同一域名反复签发失败 | 触发 CA 速率限制 | 停止测试,等限制解除 |
6.5 一个绕不开的避坑建议
最后给个建议:把 ALLinSSL 的管理端口不暴露到公网,这个一定要执行到位。证书管理系统的权限和能力太强了,一旦被攻破,等于整个域名体系的证书都能被控制,后果非常严重。我自己现在的做法是管理端口只监听 127.0.0.1,需要远程操作时用 SSH 隧道。虽然多了两步操作,但安全底线守住了。
我在实际部署中最大的体会是:别一上来就把所有域名铺进去,先用一两个不重要的域名把整条链路跑通,确认申请、续期、推送、告警都正常了,再批量迁移。跑通之后,这套体系的收益是肉眼可见的,你再也不用记着“下个月哪张证书到期”这种破事,系统会在该续期的时候自动把事情做完,出问题的时候用通知把你叫醒。落到自己手里的,只有每月一次翻日志的安心和偶尔收到一封“续期成功”通知的踏实。