OCI Portal
自托管的 OCI 多租户管理面板与 GenAI 兼容网关
界面预览 · 核心能力 · 快速开始 · 生产部署 · AI 网关 · 开发
AI 网关文档 · OCI 调用者指纹评估 · OpenAPI · 更新日志 · 前端仓库
本仓库为后端与发行仓库;前端源码位于 oci-portal-dash。
界面预览
核心能力
| 能力域 | 覆盖范围 |
|---|---|
| 租户与云资源 | 多 OCI API Key、分组、批量测活、账户画像、订阅区域缓存与切换;实例创建与电源操作、VNIC、公网 IP、保留 IP、IPv6、VCN、安全列表(规则行内编辑)、引导卷、块存储挂载、对象存储(桶 / 对象、在线预览编辑、PAR 直传分享)与限额查询 |
| 成本与账单 | 成本 / 用量查询(小时、日、月粒度,支持服务 / SKU 复合分组);发票列表与费用明细、PDF 预览下载、付款方式查询及在线支付 |
| 自动化与控制台 | 抢机、租户测活、成本同步、AI 渠道探测;执行日志、重叠防护、熔断与结果通知;xterm 串行终端、noVNC 和 OCI 控制台连接两跳 SSH 隧道 |
| 身份与审计 | IAM 用户、MFA、API Key、密码策略、SAML、通知收件人与多 Identity Domain;通过 Service Connector Hub 与 Notifications 接收并分类推送 OCI Audit 事件 |
| 通知与安全 | Telegram、Webhook、ntfy、Bark、SMTP;AES-256-GCM、JWT、bcrypt、TOTP、OIDC / GitHub 登录、通行密钥(Passkey / WebAuthn,需 HTTPS 且换域名后需重新注册)、Web3 钱包签名登录(EIP-4361,仅注入钱包与 EOA)、登录锁定、IP 限速、活跃会话管理(按设备查看与定点撤销)和操作审计 |
| AI 网关 | OpenAI Responses、Chat Completions、Embeddings 与 Anthropic Messages;渠道分组、加权路由、熔断探测、模型治理、密钥管理和调用日志 |
| 跨端体验 | 桌面与移动端响应式布局,移动端底部导航与卡片列表;PWA 可安装到主屏幕并自动更新,静态资源缓存不拦截 /api/*、/ai/* 实时请求 |
运行形态
浏览器 / API 客户端
│
▼
┌──────────────────── OCI Portal 单个 Go 进程 ────────────────────┐
│ Vue 3 静态资源(go:embed) │
│ /api/v1 → Gin → Service → OCI SDK │
│ /ai/v1 → 兼容转换与路由 → OCI Generative AI │
│ GORM → SQLite(默认)/ MySQL / PostgreSQL(experimental) │
└─────────────────────────────────────────────────────────────────┘
Note
默认推荐 SQLite 单实例部署。MySQL 和 PostgreSQL 适配仍属 experimental, 不应据此推断服务支持多副本并发运行。
快速开始
Docker Compose(推荐)
前置条件:Docker、Docker Compose v2、OpenSSL。
Caution
.env中的DATA_KEY用于解密 OCI 私钥、口令和渠道凭据。首次生成后必须长期 保存;升级或重装时不要覆盖,否则已有密文将无法恢复。
-
克隆仓库并生成一份需要长期保存的
.env:git clone https://github.com/wangdefaa/oci-portal.git cd oci-portal umask 077 printf 'DATA_KEY=%s\nJWT_SECRET=%s\nADMIN_PASSWORD=%s\n' \ "$(openssl rand -hex 32)" \ "$(openssl rand -hex 32)" \ "$(openssl rand -base64 24)" > .env chmod 600 .env -
准备数据目录:
mkdir -p dataLinux 使用 bind mount 时,需要让镜像内的 nonroot 用户(uid
65532)可写; Docker Desktop 用户通常不需要执行:sudo chown 65532:65532 data -
启动并检查状态:
docker compose up -d docker compose ps -
查看初始管理员密码并登录:
grep '^ADMIN_PASSWORD=' .env访问
http://127.0.0.1:18888,默认用户名为admin。启动异常时查看最近日志:
docker compose logs --tail=100 oci-portal
Tip
请将
.env与data/oci-portal.db成对备份;恢复时两者必须匹配。
二进制运行
Release 提供 Linux amd64 / arm64 二进制。以下以 amd64 为例;arm64 主机将文件名中的 amd64 替换为 arm64:
curl -fLO https://github.com/wangdefaa/oci-portal/releases/latest/download/oci-portal-server-linux-amd64
curl -fLO https://github.com/wangdefaa/oci-portal/releases/latest/download/SHA256SUMS
grep 'oci-portal-server-linux-amd64$' SHA256SUMS | sha256sum -c -
chmod +x oci-portal-server-linux-amd64
# 复用上文生成并妥善保存的 .env。
set -a
. ./.env
set +a
./oci-portal-server-linux-amd64
默认访问地址为 http://localhost:8080。ADMIN_PASSWORD 只在数据库中没有用户时创建初始管理员,后续启动不会用它重置密码。
源码构建
源码构建要求 Go 1.26.5、curl、unzip 和 sha256sum。仓库只保留前端占位页,编译完整单文件前应下载 DASH_VERSION 指定的前端产物并校验:
DASH_TAG="$(tr -d '\r\n' < DASH_VERSION)"
DASH_BASE="https://github.com/wangdefaa/oci-portal-dash/releases/download/${DASH_TAG}"
curl -fL -o dist.zip "${DASH_BASE}/dist.zip"
curl -fL -o dist.zip.sha256 "${DASH_BASE}/dist.zip.sha256"
sha256sum -c dist.zip.sha256
rm -rf internal/webui/dist
mkdir -p internal/webui/dist
unzip -q dist.zip -d internal/webui/dist
CGO_ENABLED=0 go build -trimpath -o bin/oci-portal-server ./cmd/server
本地构建显示 dev 版本;Release 工作流会注入正式版本和构建时间。internal/webui/dist 中的真实前端产物不应提交到仓库。
生产部署
Warning
服务本身只提供 HTTP。除本机试用外,应仅监听回环地址或容器内部网络,并由 TLS 反向代理提供 HTTPS;否则管理员密码、JWT、AI 密钥和租户凭据会经明文传输。
Caddy
portal.example.com {
reverse_proxy 127.0.0.1:18888
}
Caddy 会自动处理 WebSocket。使用 nginx、Traefik 或其他反向代理时,还需要满足:
- 为串行终端和 VNC 转发 WebSocket Upgrade 头
- 为 AI 流式响应和控制台连接设置较长的读写超时,建议
1h - 整站请求体上限至少为
10MB;后端会继续限制面板 API 为1MB、AI 网关为10MB - 将面板内「设置 → 安全 → 真实 IP 请求头」配置为反向代理实际写入的头;系统审计、登录锁定和 IP 限速依赖它
- 配置
PUBLIC_URL或面板地址,供 OAuth 回调和 OCI 日志回传链路使用
nginx 最小示例
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;
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;
proxy_read_timeout 1h;
proxy_send_timeout 1h;
}
}
若前端静态文件与后端分离部署,/api/* 和 /ai/* 必须代理到后端,其余路径由 SPA 静态服务处理并回退到 index.html。Traefik 通过容器网络连接时应直达容器端口 8080,无需暴露宿主机端口。
AI 网关
面板内置 OpenAI / Anthropic 兼容的 GenAI 网关:独立密钥鉴权(Authorization: Bearer sk-... 或 x-api-key),支持渠道分组、加权路由、熔断探测、模型黑白名单、内容日志与调用日志。
| 端点 | 定位 | 流式 |
|---|---|---|
POST /ai/v1/responses |
OpenAI Responses,无状态主接口(xAI 服务端工具 / MCP) | SSE |
POST /ai/v1/chat/completions |
OpenAI Chat Completions 兼容层 | SSE |
POST /ai/v1/messages |
Anthropic Messages 转换层 | SSE |
POST /ai/v1/embeddings |
OpenAI Embeddings | 否 |
POST /ai/v1/audio/speech |
文本转语音(xAI Voice) | 否 |
POST /ai/v1/tts |
文本转语音(xAI 官方格式) | 否 |
POST /ai/v1/rerank |
文档重排(Cohere Rerank) | 否 |
POST /ai/v1/moderations |
内容审核(OCI Guardrails) | 否 |
GET /ai/v1/models |
当前密钥可见的模型列表 | 否 |
协议兼容边界、已知上游限制与逐字段兼容矩阵见 AI 网关文档。
API 与配置
API 文档
| 路径 | 鉴权 | 用途 |
|---|---|---|
/api/v1/* |
登录返回的 JWT Bearer Token | 面板管理 API |
/ai/v1/* |
AI 网关密钥 | OpenAI / Anthropic 兼容接口 |
/api/v1/webhooks/oci-logs/:secret |
URL 中的独立回传密钥 | OCI Notifications 日志回传 |
OpenAPI 文件随仓库维护:docs/swagger.yaml · docs/swagger.json。
运行进程时设置 SWAGGER=1 可开放 /swagger/index.html。Swagger 默认关闭,生产环境建议仅在受控网络内按需开启。接口注释变更后必须重新生成 OpenAPI。
环境变量
| 变量 | 使用条件 | 默认值 | 说明 |
|---|---|---|---|
DATA_KEY |
必填 | — | 敏感字段加密主密钥;必须持久保存,不能随意轮换 |
JWT_SECRET |
必填 | — | JWT 签名密钥;更换会使已有登录令牌失效 |
ADMIN_USERNAME |
可选 | admin |
初始管理员用户名 |
ADMIN_PASSWORD |
首次启动 | — | 仅在数据库无用户时创建管理员,不会重置已有密码 |
ADDR |
可选 | :8080 |
HTTP 监听地址 |
DB_DRIVER |
可选 | sqlite |
sqlite / mysql / postgres;后两者为 experimental |
DB_PATH |
SQLite | oci-portal.db |
SQLite 文件路径 |
DB_DSN |
MySQL / PostgreSQL | — | MySQL 需 parseTime=True;不要在日志或文档中暴露凭据 |
PUBLIC_URL |
可选 | — | 面板公网基址,作为 OAuth 回调和日志回传引导的回退值 |
TZ |
可选 | 系统时区 | cron 表达式的解释时区;容器示例使用 Asia/Shanghai |
HTTP_PROXY / HTTPS_PROXY / NO_PROXY |
可选 | — | Go 标准出站代理变量;面板内显式代理配置优先用于对应业务 |
SWAGGER |
可选 | 关闭 | 设为 1 时开放 Swagger UI |
GIN_MODE |
可选 | release |
debug / release |
升级与备份
- 阅读 CHANGELOG,确认目标版本的行为变化。
- 备份
.env和数据库。SQLite Compose 部署建议先停止服务,再复制data/oci-portal.db,避免在线复制产生不一致快照。 - 保持原
DATA_KEY不变;只有数据库而没有对应密钥时,敏感字段无法解密。 - Compose 部署执行
docker compose pull,再执行docker compose up -d;服务启动时 会自动完成数据库迁移。 - 生产环境保持 Swagger 关闭、限制管理面访问来源,并为 OCI API Key 配置最小权限。
开发
gofmt -l .
go vet ./...
go test ./...
# Handler 注释变更后重新生成唯一的对外 API 文档。
go tool swag init -g cmd/server/main.go -o docs --parseInternal --parseDependency --overridesFile docs/.swaggo
- Go 后端规范与目录约定:
AGENTS.md·.trellis/spec/backend/ - 前端开发与构建:oci-portal-dash
- 版本变更:
CHANGELOG.md
致谢
感谢 Yohann0617/oci-helper 为本项目提供思路。





