Files
openresty-gateway/README.md
2026-05-19 10:10:03 +08:00

233 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenResty Gateway
这个目录用于通过 Docker Compose 启动 OpenResty 网关,并使用 Certbot 申请和续期 Let's Encrypt 证书。
## 前置条件
- Linux 服务器
- Docker 和 Docker Compose
- `openssl`
- `crontab`,可选,用于安装自动续期任务
- 域名 DNS 已解析到当前服务器
当前配置使用 `network_mode: host`OpenResty 会直接监听宿主机端口。
## 脚本结构
- `init-certs.sh`:首次初始化入口,内部调用 `scripts/init-certs-core.sh`
- `add-domain-certs.sh`:在 OpenResty 已运行时追加新域名证书,内部调用 `scripts/add-domain-certs-core.sh`
- `reload.sh`:修改 nginx 配置后校验并重载 OpenResty。
- `uninstall.sh`:卸载入口,目前用于卸载证书自动续期 cron。
- `scripts/`:放具体实现脚本,包括 nginx 域名模板生成、证书初始化核心逻辑、手动续期、安装和卸载续期 cron。
## 首次部署
进入目录:
```bash
cd /path/to/openresty-gateway
```
如果需要直接执行脚本,可以先添加执行权限:
```bash
chmod +x *.sh scripts/*.sh
```
首次申请证书并启动服务:
先确认 `init-certs.sh` 里的 `DOMAINS``CERT_EMAIL` 已经按当前部署环境配置好。
```bash
sh init-certs.sh
```
默认情况下,脚本只校验 nginx 配置是否存在,不会自动创建新站点配置。缺配置时可以显式生成基础模板:
```bash
sh init-certs.sh --create-missing-conf
```
这个脚本会:
1. 校验每个域名都有 nginx 配置、配置里放行 `/.well-known/acme-challenge/`,且 nginx 引用的证书域名都已加入 `DOMAINS`
2. 为缺失的证书路径生成临时 dummy 证书。
3. 启动 OpenResty保证 `/.well-known/acme-challenge/` 可以访问。
4. 删除本次创建的 dummy 证书文件。
5. 运行 Certbot 分别为每个域名申请正式证书。
6. 重启 OpenResty 让正式证书生效。
7. 如果系统有 `crontab`,安装证书自动续期 cron 任务。
不想在初始化时安装自动续期任务:
```bash
sh init-certs.sh --skip-renew-cron
```
重复执行 `init-certs.sh` 不会强制重签已有证书Certbot 会保留还没到期的证书。
重复执行时也不会重复添加 cron安装脚本会先删除旧任务块再写入新任务。
## 追加域名证书
当 OpenResty 已经在线运行,只需要给新域名补证书时,使用 `add-domain-certs.sh`
先把要新增的域名写入 `add-domain-certs.sh``DOMAINS`,这里只放本次要新增的域名:
```sh
DOMAINS="
proxy.sggai.site
gitea.sggai.site
"
```
然后执行:
```bash
sh add-domain-certs.sh
```
这个脚本会:
1. 校验 Docker Compose 配置,并确认 `openresty` 容器已经在运行。
2. 检查每个新增域名是否已有 nginx 配置。
3. 如果缺少 `conf/conf.d/<domain>.conf`,自动调用 `scripts/ensure-domain-conf.sh` 生成基础模板。
4. 为缺失证书的新域名生成临时 dummy 证书。
5. 校验并重载 OpenResty让新增配置和 dummy 证书生效。
6. 检查本机和公网 HTTP-01 challenge 路径是否可访问。
7. 删除本次创建的 dummy 证书,调用 Certbot 申请正式证书。
8. 再次重载 OpenResty让正式证书生效。
如果服务器无法从本机访问自己的公网域名,但外部访问是正常的,可以跳过公网探测:
```bash
sh add-domain-certs.sh --skip-public-http-check
```
自动生成的 nginx 配置是静态站点基础模板,只保证证书申请和 HTTPS 站点能启动。如果新域名需要反向代理到后端服务,请按业务需要修改 `conf/conf.d/<domain>.conf`,再执行:
```bash
sh reload.sh
```
## 日常启动和停止
启动:
```bash
docker compose up -d openresty
```
停止:
```bash
docker compose down
```
重启:
```bash
docker compose restart openresty
```
检查配置:
```bash
docker compose config
docker compose exec openresty openresty -t
```
查看日志:
```bash
docker compose logs -f openresty
```
## 证书续期
手动续期:
```bash
sh scripts/renew-certs.sh
```
`scripts/renew-certs.sh` 使用 `certbot renew`Certbot 会自己判断证书是否快过期;没到续期时间不会真正重签。
## 安装自动续期
安装每天 03:00 自动续期:
```bash
sh scripts/install-renew-cron.sh
```
安装脚本可以重复执行。它会先删除旧的自动续期任务块,再写入新的任务,避免重复添加。
自定义执行时间,例如每天 04:30
```bash
SCHEDULE="30 4 * * *" sh scripts/install-renew-cron.sh
```
查看当前 crontab
```bash
crontab -l
```
卸载自动续期:
```bash
sh uninstall.sh
```
自动续期日志:
```bash
tail -f logs/cert-renew.log
```
## AI 网关 mock 规则
`conf/conf.d/000-ai.sggai.site-mock-small-chat.conf` 会优先于 `ai.sggai.site.conf` 加载。
它会拦截:
- 路径:`/v1/chat/completions`
- 方法:`POST`
- JSON 中 `"stream": false`
- 请求体不超过 `1024` 字节
- `messages` 文本内容总长度不超过 `20` 字节
命中后直接返回 mock 响应:
```json
{
"id": "chatcmpl-mock",
"object": "chat.completion",
"created": 1716030000,
"model": "xxx",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "ok" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2 }
}
```
不满足 mock 条件的请求会继续转发到:
```text
http://10.1.0.1:3001
```
## 注意事项
- `certs/``logs/`、运行时 webroot 文件默认不提交到 Git。
- `conf/conf.d/00-default-deny.conf` 是默认拒绝站点,用于丢弃没有匹配到具体 `server_name` 的 HTTP 请求,并拒绝未知 SNI 的 HTTPS 握手。
- 如果证书文件不存在OpenResty 的 HTTPS 配置会启动失败;首次部署请先运行 `init-certs.sh`
- `ai.sggai.site` 当前通过 `000-` 前缀配置文件覆盖原配置,`openresty -t` 可能出现同名 server 被忽略的 warning。
- 如果需要透传带下划线的请求头,例如 `Session_id`,需要确认 Nginx 的 `underscores_in_headers` 策略是否符合预期。