ohmyapi commited on
Commit
be2951a
·
1 Parent(s): 8b4dc02

feat: upgrade to PostgreSQL mode (Neon) + serve static landing page

Browse files

- Serve static/index.html at root instead of 302 redirect
- Update README for PostgreSQL mode with Neon DATABASE_URL
- Secrets configured: DATABASE_URL, CLAUDE_SESSION_KEYS

Files changed (3) hide show
  1. Dockerfile +1 -0
  2. README.md +30 -218
  3. nginx.conf +4 -2
Dockerfile CHANGED
@@ -4,6 +4,7 @@ FROM nginx:1.27-alpine
4
 
5
  COPY --from=upstream /claude2api /usr/local/bin/claude2api
6
  COPY nginx.conf /etc/nginx/conf.d/default.conf
 
7
  COPY entrypoint.sh /entrypoint.sh
8
 
9
  EXPOSE 7860
 
4
 
5
  COPY --from=upstream /claude2api /usr/local/bin/claude2api
6
  COPY nginx.conf /etc/nginx/conf.d/default.conf
7
+ COPY static/index.html /usr/share/nginx/html/index.html
8
  COPY entrypoint.sh /entrypoint.sh
9
 
10
  EXPOSE 7860
README.md CHANGED
@@ -8,235 +8,47 @@ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
- # Claude2API — Hugging Face Space 说明
12
 
13
  当前 Space:<https://ohmyapi-c2api.hf.space>
14
 
15
- 这是一个围绕 `pushzx/claude2api:latest` 的 Hugging Face Docker Space 包装层。目标很克制:
16
-
17
- - 让根路径 `/` 直接进入真实可用的管理登录页 `/admin/login`
18
- - 保持 `/admin`、`/health`、`/v1/*` 等能力继续由上游 `claude2api` 提供
19
- - wrapper 只处理入口体验与反代,不在外层伪造持久化配置语义
20
 
21
  ## 当前部署状态
22
 
23
- 当前线上状态已经收敛为 **public Space + simple mode**
24
-
25
- - Space 类型:**public Space**
26
- - 运行模式:**simple mode**
27
- - 当前不启用 DB-backed 持久化
28
- - 当前已从 Space Secrets 中移除:`DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASS`、`DB_NAME`、`PGSSLMODE`
29
- - 当前根路径 `/` 会直接 `302` 到 `/admin/login`
30
-
31
- 这样收敛的原因很明确:simple mode 已经稳定可用,而当前上游镜像的 DB-only 路径对 Neon / Supabase 这类强制 TLS 的托管 PostgreSQL 仍未验证通过,不能在这里把它写成现成功能。
32
-
33
- ## 当前访问行为
34
-
35
- public Space 的含义是:**入口默认公开**,不是 **Secrets 自动公开**。
36
-
37
- 当前线上已验证:
38
-
39
- - `/` → `302 /admin/login`
40
- - `/admin/login` 可正常打开
41
- - `/health` 返回 `200`
42
- - `/v1/messages` 未带正确 token 时返回 `401 Invalid API key`
43
- - 带正确 app token 时,`claude-sonnet-4-6` 已成功完成实际调用
44
- - `/v1/models` 可在带 token 的情况下返回模型列表
45
-
46
- ## public Space 的风险边界
47
-
48
- public Space 不会因为是 public 就把 Hugging Face Secrets 直接暴露出来,但它会让你的入口地址处于公网可探测状态。
49
-
50
- 这意味着:
51
-
52
- - `https://ohmyapi-c2api.hf.space/` 这类地址任何人都能访问与探测
53
- - Hugging Face Space Secrets **不会**被页面或公开 API 直接回显
54
- - 真正更常见的泄露面是:把 token / session 写进仓库文件、前端页面、日志、导出的配置或本机历史文件
55
- - public Space 是否安全,关键不在于“是否 public”,而在于:
56
- - app 自身接口是否强制鉴权
57
- - `CLAUDE_API_KEY` / `CLAUDE_SESSION_KEYS` 是否只保留在服务端运行时环境
58
- - 仓库与页面输出里是否完全不出现真实 secret
59
-
60
- 换句话说,public Space **不会自动泄露 session**,但如果 app token 泄露、接口未加保护,别人就能直接消费你的服务。
61
-
62
- ## 为什么 Hugging Face 环境变量能直接生效
63
-
64
- 因为当前 Space 使用的是 **Docker SDK**。
65
-
66
- Hugging Face 对 Docker Space 的处理方式不是“把变量写进仓库文件”,而是在容器启动时把 Space Settings 里的:
67
-
68
- - **Variables**
69
- - **Secrets**
70
-
71
- 直接注入成容器进程的真实运行时环境变量。
72
-
73
- 对这个仓库来说,等价于容器启动时直接拿到了例如:
74
-
75
- ```env
76
- ADMIN_USER=admin
77
- LISTEN_ADDR=:7860
78
- CLAUDE_API_KEY=...
79
- ADMIN_PASS=...
80
- CLAUDE_SESSION_KEYS=...
81
- ```
82
-
83
- 因此,只要上游 `claude2api` 在启动时通过 `os.Getenv(...)` 或等价方式读取配置,它就会直接生效,不需要额外写入 `.env`、`config.yaml` 或其它文件。
84
-
85
- ### 当前已确认的 Space Variables
86
-
87
- 当前公开可读到的 Variables 是:
88
-
89
- ```env
90
- LISTEN_ADDR=:7860
91
- ADMIN_USER=admin
92
- ```
93
-
94
- Secrets 不会被 Hugging Face API 直接回显,但从线上行为可以确认至少存在并已生效:
95
-
96
- - `CLAUDE_API_KEY`
97
- - `CLAUDE_SESSION_KEYS`
98
- - `ADMIN_PASS`
99
-
100
- ## 当前 wrapper 做了什么
101
-
102
- 当前 `Dockerfile` 不是直接把上游镜像原样暴露到 `:7860`,而是:
103
-
104
- - 前置一个很薄的 nginx
105
- - nginx 监听 `:7860`
106
- - 上游 `claude2api` 在容器内监听 `127.0.0.1:8080`
107
- - `/` 与 `/index.html` 直接跳转到 `/admin/login`
108
- - 其余路径继续透传到上游
109
-
110
- 这样做的原因很简单:
111
-
112
- - 旧版 root path 会显示 `404 page not found`
113
- - 现在用户访问根路径时,会直接进入真实可用的登录入口
114
- - 同时不需要去改上游镜像源码
115
-
116
- ## 当前为什么不启用 PostgreSQL 持久化
117
-
118
- ### 结论
119
-
120
- **按当前已验证状态,不能认为这个 Space 已经配置并启用了 PostgreSQL 持久化存储。**
121
-
122
- 更准确地说:当前线上已经明确收敛为 **simple mode only**,不是“正在尝试 DB-only 但尚未成功”。
123
-
124
- ### 原因
125
-
126
- 1. 只要存在 `CLAUDE_SESSION_KEYS`,上游就可以走 simple mode,并且当前已验证可稳定提供 API 能力。
127
- 2. 当前 Hugging Face Space runtime 已确认 `storage.current = None` 且 `storage.requested = None`,因此容器内本地 PostgreSQL 不能视为正式持久化层。
128
- 3. 对当前上游镜像的排查显示,DB-only 路径很可能会把 PostgreSQL DSN 拼成:
129
-
130
- ```text
131
- host=%s port=%s user=%s password=%s dbname=%s sslmode=disable
132
- ```
133
-
134
- 这会与 Neon / Supabase 这类强制 TLS 的托管 PostgreSQL 冲突。
135
- 4. 因此,即使文档里存在“可���接外部数据库”的描述,也不能把它等同于“当前镜像已支持外部托管 PG 持久化”。
136
-
137
- ### 为什么 local PostgreSQL 不能当成 HF 持久化
138
-
139
- 如果你打算在 Hugging Face Space 容器里直接放一个“本地 PostgreSQL”,要先明确一件事:**默认情况下,这不等于可靠持久化。**
140
-
141
- 原因是:
142
-
143
- 1. Docker Space 默认使用的是容器自身的可写层,而不是天然持久卷。
144
- 2. 如果没有单独申请 Hugging Face persistent storage,并把数据库目录明确挂到持久路径,本地 PG 数据在 restart / rebuild / redeploy 后都可能丢失。
145
- 3. 当前这个 Space 没有启用 persistent storage,因此“容器内本地 PG”不能当成正式配置持久化方案。
146
-
147
- 因此:
148
-
149
- - 本地 PG 更适合临时调试,不适合承担当前 Space 的正式配置持久化
150
- - 真正需要稳定持久化时,应优先使用外部 PostgreSQL,或者先补齐 HF persistent storage,再验证上游是否支持对应的数据目录语义
151
-
152
- ## 当前推荐的线上配置思路
153
-
154
- 如果你只是想把 Space 稳定跑起来,当前推荐就是保持 simple mode:
155
-
156
- ### 必要 Secrets
157
-
158
- - `CLAUDE_SESSION_KEYS`
159
- - `CLAUDE_API_KEY`
160
- - `ADMIN_PASS`
161
-
162
- ### 当前 Variables
163
-
164
- ```env
165
- LISTEN_ADDR=:7860
166
- ADMIN_USER=admin
167
- ```
168
-
169
- ### 当前不启用的配置
170
-
171
- 以下 DB 相关项当前视为**暂不启用**,不要再把它们当成线上必需配置:
172
-
173
- - `DB_HOST`
174
- - `DB_PORT`
175
- - `DB_USER`
176
- - `DB_PASS`
177
- - `DB_NAME`
178
- - `PGSSLMODE`
179
-
180
- ## 当前已验证可调用的模型
181
-
182
- 带正确 app token 时,以下模型已通过真实 `/v1/messages` 请求验证,可以正常返回结果:
183
-
184
- - `claude-sonnet-4-5`
185
- - `claude-haiku-4-5`
186
- - `claude-sonnet-4-6`
187
- - `claude-haiku-4-6`
188
- - `claude-3-5-sonnet-20241022`
189
- - `claude-3-5-haiku-20241022`
190
- - `claude-3-sonnet-20240229`
191
- - `claude-3-haiku-20240307`
192
-
193
- 以下模型虽然会出现在 `/v1/models` 列表里,但当前实测返回的是 `403 model_not_available`:
194
-
195
- - `claude-opus-4-5`
196
- - `claude-opus-4-6`
197
- - `claude-3-opus-20240229`
198
-
199
- 这也说明一件事:**`/v1/models` 返回的是“当前镜像声明支持的模型列表”,真正能否调用仍然取决于当前 session / account 的实际可用性。**
200
-
201
- ## 关于 admin password / auth token 持久化的当前结论
202
-
203
- 目前已做过的验证结论是:
204
-
205
- - `api_key` 可以在当前运行期通过管理接口更新,并立即影响鉴权结果
206
- - 但容器重启后,会回退到启动时环境变量 / HF Secrets 的值
207
- - `admin_pass` 目前看**不能**通过现有 settings 路径真正更新并持久生效
208
-
209
- 所以当前更准确的理解是:
210
 
211
- - Hugging Face Secrets / Variables = **启动配置源**
212
- - 上游 admin UI 的部分设置 = **运行期状态修改**
213
- - 两者目前**不是**一个可自动回写、可稳定持久继承的统一配置层
214
 
215
- ## 当前仓库文件职责
 
 
 
 
 
 
216
 
217
- - `Dockerfile`:构建 HF Space 容器
218
- - `nginx.conf`:把根路径重定向到 `/admin/login`,并透传其他请求
219
- - `entrypoint.sh`:同时启动前置 nginx 和上游 `claude2api`
220
- - `.env.example`:本地 / VPS 运行示例,不代表 HF Secrets 会被运行时回写
221
- - `docker-compose.yml`:本地 / VPS 参考,不会直接在 HF Space 中运行
222
 
223
- ## 最小验收命令
 
 
 
 
 
224
 
225
- ```bash
226
- curl -I https://ohmyapi-c2api.hf.space/
227
- curl https://ohmyapi-c2api.hf.space/health
228
 
229
- curl https://ohmyapi-c2api.hf.space/v1/models \
230
- -H "Authorization: Bearer $CLAUDE_API_KEY"
 
 
231
 
232
- curl https://ohmyapi-c2api.hf.space/v1/messages \
233
- -H "Content-Type: application/json" \
234
- -H "Authorization: Bearer $CLAUDE_API_KEY" \
235
- -d '{
236
- "model": "claude-sonnet-4-6",
237
- "max_tokens": 32,
238
- "messages": [{"role": "user", "content": "Reply with exactly: ok"}]
239
- }'
240
- ```
241
 
242
- 如果最后一条返回正常消息体,就说明当前公开 Space、app token、以及 Claude session 这三层链路都已经打通。
 
 
 
 
8
  pinned: false
9
  ---
10
 
11
+ # Claude2API — Hugging Face Space
12
 
13
  当前 Space:<https://ohmyapi-c2api.hf.space>
14
 
15
+ 围绕 `pushzx/claude2api:latest` 的 Hugging Face Docker Space 包装层。
 
 
 
 
16
 
17
  ## 当前部署状态
18
 
19
+ - **运行模式**:PostgreSQL 模式(Neon 托管数据库)
20
+ - **数据库**:通过 `DATABASE_URL` 连接 Neon PostgreSQL(强制 TLS)
21
+ - **功能**:完整账号管理、健康检测、模型映射、限速、API Key 管理
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ ## 访问入口
 
 
24
 
25
+ | 路径 | 说明 |
26
+ |---|---|
27
+ | `/` | 静态落地页,引导进入管理面板 |
28
+ | `/admin` | 上游管理面板(账号/代理/模型映射/metrics) |
29
+ | `/health` | 健康检查 |
30
+ | `/v1/messages` | Anthropic 兼容 API |
31
+ | `/v1/models` | 模型列表 |
32
 
33
+ ## HF Space Secrets
 
 
 
 
34
 
35
+ | 变量 | 用途 |
36
+ |---|---|
37
+ | `DATABASE_URL` | Neon PostgreSQL 完整 DSN |
38
+ | `CLAUDE_SESSION_KEYS` | 逗号分隔的 Session Keys(启动时导入) |
39
+ | `CLAUDE_API_KEY` | API 访问密钥 |
40
+ | `ADMIN_PASS` | 管理面板密码 |
41
 
42
+ ## HF Space Variables
 
 
43
 
44
+ | 变量 | 值 |
45
+ |---|---|
46
+ | `LISTEN_ADDR` | `:7860` |
47
+ | `ADMIN_USER` | `admin` |
48
 
49
+ ## wrapper 职责
 
 
 
 
 
 
 
 
50
 
51
+ - `Dockerfile`:构建容器(nginx + claude2api 二进制)
52
+ - `nginx.conf`:根路径 serve 静态落地页,其余透传上游
53
+ - `entrypoint.sh`:同时启动 nginx 和 claude2api
54
+ - `static/index.html`:落地页
nginx.conf CHANGED
@@ -12,11 +12,13 @@ server {
12
  client_max_body_size 50m;
13
 
14
  location = / {
15
- return 302 https://$host/admin/login;
 
16
  }
17
 
18
  location = /index.html {
19
- return 302 https://$host/admin/login;
 
20
  }
21
 
22
  location = /favicon.ico {
 
12
  client_max_body_size 50m;
13
 
14
  location = / {
15
+ root /usr/share/nginx/html;
16
+ try_files /index.html =404;
17
  }
18
 
19
  location = /index.html {
20
+ root /usr/share/nginx/html;
21
+ try_files /index.html =404;
22
  }
23
 
24
  location = /favicon.ico {