发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
CI / test (push) Successful in 30s
Release / release (push) Successful in 49s

This commit is contained in:
Wang Defa
2026-07-10 17:38:34 +08:00
parent 4af6a0ca92
commit dbba1f4905
78 changed files with 6898 additions and 551 deletions
+81 -4
View File
@@ -35,10 +35,10 @@
- **抢机任务**:cron 周期尝试创建实例直到成功,支持熔断与通知
- **网页控制台**:实例串行控制台(xterm)与 VNC(noVNC),两跳 SSH 隧道
- **AI 网关**OpenAI / Anthropic 兼容端点转发 OCI GenAI(对话/Responses/Embeddings),号池渠道加权负载均衡、熔断探测、密钥管理与用量日志
- **日志回传**OCI Audit 事件经 Connector Hub → Notifications HTTPS 订阅回传入库,一键创建链路
- **租户治理**IAM 用户/MFA/API Key 管理、密码策略、身份提供商(SAML)、通知收件人
- **安全**JWT + bcrypt、TOTP 两步验证、OIDC/GitHub 外部登录、登录锁定、IP 限速、真实 IP 头可配、系统操作审计
- **通知**Telegram 模板化推送(测活/抢机/成本/锁定等事件)
- **日志回传**OCI Audit 事件经 Connector Hub → Notifications HTTPS 订阅回传入库,一键创建链路;自定义告警规则(事件类型/来源 IP 白名单/资源/频率阈值)命中即推送
- **租户治理**IAM 用户/MFA/API Key 管理、密码策略、身份提供商(SAML)、通知收件人;多 Identity Domain 租户可按域切换管理
- **安全**JWT + bcrypt(凭据变更旧令牌立即失效,可一键撤销全部会话)、TOTP 两步验证、OIDC/GitHub 外部登录、登录锁定、IP 限速、真实 IP 头可配、请求体/超时防护、系统操作审计
- **通知**模板化推送,五渠道并存(Telegram / Webhook / ntfy / Bark / SMTP),Webhook 可对接飞书、钉钉、Slack、企业微信机器人
## 快速开始
@@ -55,9 +55,13 @@ DATA_KEY=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32) ADMIN_PASSWO
### Docker Compose
```bash
# 镜像以 distroless nonroot(uid 65532)运行,数据卷需可写,否则 SQLite 报 unable to open database file
mkdir -p ./data && sudo chown 65532:65532 ./data
DATA_KEY=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32) ADMIN_PASSWORD=<初始密码> docker compose up -d
```
默认只监听 `127.0.0.1:18888`;公网访问须置于 TLS 反向代理之后,见下文「反向代理」。
### 源码构建(单文件,含前端)
```bash
@@ -72,6 +76,78 @@ CGO_ENABLED=0 go build -trimpath \
> 注意:上述解压会覆盖仓库占位文件 `internal/webui/dist/index.html`,提交代码前勿把真实产物带入版本库。
### 反向代理(公网部署必读)
面板自身只提供 HTTP,管理员口令、JWT 与租户 API 私钥都会经明文承载。除本机试用外,应让面板仅监听回环地址(compose 示例已默认 `127.0.0.1:18888`),由支持 TLS 的反向代理对外提供 HTTPS。
Caddy 最小示例(整站反代,自动申请并续期 Let's Encrypt 证书,WebSocket 自动透传):
```caddyfile
portal.example.com {
reverse_proxy 127.0.0.1:18888
}
```
nginx 示例(证书自备;Web Console 的 WebSocket 升级与长超时必须显式配置,否则串行终端连不上或空闲即断):
```nginx
# http 块内:按请求是否升级为 WebSocket 决定 Connection 头
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
server {
listen 443 ssl;
server_name portal.example.com;
ssl_certificate /etc/nginx/certs/portal.example.com.crt;
ssl_certificate_key /etc/nginx/certs/portal.example.com.key;
# 放行到最大入口(AI 网关 10MB);各入口更细的上限由后端自身执行
client_max_body_size 10m;
location / {
proxy_pass http://127.0.0.1:18888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# WebSocket 空闲与 AI 流式响应都需要长读超时(默认 60s 会断)
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
}
```
Traefik 示例(已运行 Traefik 的 Docker 环境,面板容器加 label 接入即可,WebSocket 透明支持):
```yaml
services:
oci-portal:
image: ghcr.io/wangdefaa/oci-portal:latest
# ……环境变量与数据卷同上文 compose 示例;与 Traefik 同一 docker 网络,
# Traefik 经容器网络直达 8080,无需(也不应)对外映射 ports
labels:
- traefik.enable=true
- traefik.http.routers.oci-portal.rule=Host(`portal.example.com`)
- traefik.http.routers.oci-portal.entrypoints=websecure
- traefik.http.routers.oci-portal.tls.certresolver=le # 换成你的 certResolver 名
- traefik.http.services.oci-portal.loadbalancer.server.port=8080
```
若前端静态文件由反代直接伺服(不走内嵌页面),则按前缀代理,缺一不可:
| 前缀 | 内容 | 何时需要 |
| --- | --- | --- |
| `/api/*` | 面板 REST、Web Console WebSocket、日志回传 webhook | 始终 |
| `/ai/*` | AI 网关(OpenAI / Claude 兼容端点,独立密钥鉴权) | 启用 AI 网关时 |
| 其余路径 | 前端 SPA 静态文件(404 回退 `index.html` | 静态分离形态 |
- 反代默认追加的 `X-Forwarded-For` 用于还原真实客户端 IP,系统日志留痕、登录锁定与 IP 限速都依赖它
- 请求体上限建议与后端一致:`/api/*` 1MB、`/ai/*` 10MBCaddy 用 `request_body` 按前缀分层)
## 环境变量
| 变量 | 必填 | 默认值 | 说明 |
@@ -88,6 +164,7 @@ CGO_ENABLED=0 go build -trimpath \
| `HTTPS_PROXY` | 否 | 无 | 出站代理(如 Telegram 通知走代理) |
| `TZ` | 否 | 系统 | cron 表达式解释时区(容器内建议显式设置,二进制已嵌 tzdata) |
| `SWAGGER` | 否 | 关 | `1` 时开放 `/swagger/index.html` API 文档(生产建议按需临时开启) |
| `GIN_MODE` | 否 | `release` | `debug` / `release`,影响日志与调试输出 |
## 开发