99 lines
3.5 KiB
Markdown
99 lines
3.5 KiB
Markdown
# 证书管理服务(acme.sh)
|
||
|
||
用宿主机上的 [acme.sh](https://github.com/acmesh-official/acme.sh) 管理 Let's Encrypt 证书:
|
||
纯 Shell 实现,不依赖 Python / snap / Docker 容器。
|
||
|
||
## 为什么换成 acme.sh
|
||
|
||
之前用 certbot 容器时有个绕不开的别扭点:certbot 的 `--deploy-hook` 在**容器内**执行,
|
||
而我们要 reload 的 nginx 是**宿主机上的容器**,只能在容器里挂 `docker.sock`(等于把宿主机
|
||
root 交给容器),或者退而求其次每天无条件发一次 HUP。
|
||
|
||
acme.sh 直接跑在宿主机,`--reloadcmd` 天然在宿主机执行,**只在证书真正更新时才 reload**,
|
||
顺带把 certbot 容器、Dockerfile、docker.sock、compose PATH 问题全部消掉。
|
||
|
||
## 架构
|
||
|
||
```
|
||
宿主机 容器
|
||
───────────────────────────────────── ──────────────────────────
|
||
acme.sh(~/.acme.sh,自带 cron)
|
||
├─ 写挑战文件 ──▶ /var/www/certbot ──bind mount(ro)──▶ nginx-proxy
|
||
├─ 写证书 ──▶ /etc/letsencrypt ──bind mount(ro)──▶ nginx-proxy
|
||
└─ 续签后执行 reloadcmd: docker kill -s HUP nginx-proxy
|
||
|
||
用户 ─▶ frps(80/443) ─▶ frpc ─▶ nginx-proxy(80/8443)
|
||
```
|
||
|
||
## 目录约定
|
||
|
||
| 宿主机路径 | 用途 |
|
||
|---|---|
|
||
| `/var/www/certbot` | ACME HTTP-01 挑战文件 |
|
||
| `/etc/letsencrypt/live/<CERT_NAME>/` | 证书(默认 CERT_NAME=stonelan.cn) |
|
||
| `nginx/ssl.d/` | HTTPS server 块,证书就绪后由 `enable-ssl.sh` 写入 |
|
||
|
||
5 个域名合成**一张 SAN 证书**,放在同一个目录,nginx 的 5 个 server 块都引用它。
|
||
|
||
## 使用方法
|
||
|
||
### 1. 安装
|
||
|
||
```bash
|
||
cd common-server-public/acme
|
||
chmod +x install.sh issue.sh renew.sh check-cert.sh
|
||
./install.sh
|
||
```
|
||
|
||
### 2. 申请证书(一键引导)
|
||
|
||
```bash
|
||
sudo ./issue.sh
|
||
```
|
||
|
||
依次完成:建目录 → 起 nginx(此时无 HTTPS 配置)→ 申请证书 → 安装证书 →
|
||
写入 `ssl.d/` 并重载 nginx。
|
||
|
||
可用环境变量覆盖:
|
||
|
||
```bash
|
||
EMAIL=you@example.com \
|
||
CERT_NAME=stonelan.cn \
|
||
DOMAINS="fastgpt.stonelan.cn gitea.stonelan.cn image.stonelan.cn registry.stonelan.cn www.stonelan.cn" \
|
||
sudo -E ./issue.sh
|
||
```
|
||
|
||
### 3. 自动续签
|
||
|
||
`install.sh` 已让 acme.sh 自己写入 cron,**无需额外配置**。
|
||
|
||
建议再加一条兜底告警(`crontab.example`):
|
||
|
||
```cron
|
||
0 8 * * * bash <绝对路径>/check-cert.sh >> /var/log/acme-check.log 2>&1
|
||
```
|
||
|
||
## 故障排查
|
||
|
||
```bash
|
||
acme.sh --list # 已申请的证书
|
||
acme.sh --cron --debug 2 # 带调试跑一次续签
|
||
./check-cert.sh # 剩余天数
|
||
|
||
# 确认 nginx 只加载了 HTTP 配置(冷启动时属正常)
|
||
docker exec nginx-proxy nginx -T | grep -c "listen 8443"
|
||
|
||
# ACME 路径可达性
|
||
echo probe | sudo tee /var/www/certbot/.well-known/acme-challenge/test
|
||
curl -i http://fastgpt.stonelan.cn/.well-known/acme-challenge/test
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. 需要 root(或 sudo)运行:要写 `/etc/letsencrypt` 和 `/var/www`
|
||
2. nginx 容器 bind mount 的是**宿主机路径**,宿主机上这两个目录必须存在,
|
||
否则 docker 会自动创建成 root 所有的空目录
|
||
3. 挑战文件需要让容器内 nginx 可读,目录保持 755(`issue.sh` 已处理)
|
||
4. CA 已显式固定为 Let's Encrypt(acme.sh 3.x 默认是 ZeroSSL)
|
||
5. 证书有效期 90 天,acme.sh 默认在剩余 30 天内续签
|