Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,11 @@ Open <http://127.0.0.1:17890/panel> (the bare host also serves it):
* **rebind device identity** — see below
* live tail of the gateway log, auto-refresh

If `api_keys` is set, the panel's JSON API requires it (the page itself stays
public so you can enter the key); the key is kept in `localStorage`.
If `api_keys` is set, `/` and `/panel` are a login form until you sign in with
that key. The browser keeps an HttpOnly session cookie — not the key, and not
in `localStorage`. That cookie unlocks `/api/panel/*` only. Model clients still
send `Authorization: Bearer` or `x-api-key`; a panel session is rejected on
`/v1/*`. With no `api_keys`, the panel stays open for localhost use.

## Account identity (device fingerprint)

Expand Down Expand Up @@ -207,7 +210,7 @@ Environment variables override it:
| `LOOMY_API_KEYS` | comma-separated gateway keys (`[]` = no auth) |
| `LOOMY_DEFAULT_MODEL` | fallback model |
| `LOOMY_ACCOUNTS_FILE` / `LOOMY_LOG_DIR` | state locations |
| `LOOMY_PROXY` | e.g. `http://127.0.0.1:7877` (default: direct) |
| `LOOMY_PROXY` | `socks5://`, `http://`, or `https://host:port` (default: direct). SOCKS5 resolves DNS at the proxy. The panel can change it at runtime. |
| `LOOMY_STRATEGY` | `balance` / `round_robin` / `lru` |

### Protecting the gateway
Expand All @@ -217,7 +220,8 @@ Environment variables override it:
```

Clients then send `Authorization: Bearer sk-local-whatever` or
`x-api-key: sk-local-whatever`. `/health` stays public for probes.
`x-api-key: sk-local-whatever`. The same key is what you type into the panel
login page. `/health` stays public for probes.

## Docker

Expand Down Expand Up @@ -339,11 +343,14 @@ By default the gateway binds `127.0.0.1` — only your machine can reach it.
To share it on your LAN or the internet:

1. **Set an API key first.** Without `api_keys`, anyone who can reach the port
spends your account's points:
spends your account's points, and the panel has no login page:

```json
{ "api_keys": ["sk-something-long-and-random"] }
```

Opening the site then shows a login form. The key is checked and discarded;
it is not stored in the browser.
2. Then `LOOMY_HOST=0.0.0.0` (or `"host": "0.0.0.0"` in `config.json`).
3. Put a reverse proxy with TLS in front if it's public. Caddy example:

Expand Down
15 changes: 10 additions & 5 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,11 @@ export ANTHROPIC_API_KEY=随便填
* **重绑设备标识**(见下一节)
* 实时日志尾巴,可自动刷新

如果配置了 `api_keys`,面板的接口就需要这个 Key(页面本身保持公开,方便你填 Key),
Key 存在浏览器 localStorage 里。
如果配置了 `api_keys`,打开 `/` 或 `/panel` 会先看到登录页,用这把 Key 登录。
浏览器只保存一个 HttpOnly 会话 Cookie,不保存 Key 本身,也不再写入
`localStorage`。这张 Cookie 只能访问 `/api/panel/*`。模型客户端仍然发送
`Authorization: Bearer` 或 `x-api-key`;面板会话访问 `/v1/*` 会被拒绝。
不配置 `api_keys` 时面板保持开放,只适合本机使用。

## 账号设备标识(指纹)

Expand Down Expand Up @@ -193,7 +196,7 @@ Key 存在浏览器 localStorage 里。
| `LOOMY_API_KEYS` | 网关自己的 Key,逗号分隔(`[]` = 不鉴权) |
| `LOOMY_DEFAULT_MODEL` | 兜底模型 |
| `LOOMY_ACCOUNTS_FILE` / `LOOMY_LOG_DIR` | 状态文件位置 |
| `LOOMY_PROXY` | 如 `http://127.0.0.1:7877`(默认直连) |
| `LOOMY_PROXY` | `socks5://`、`http://` 或 `https://主机:端口`(默认直连)。SOCKS5 由代理解析域名。面板里也能改,立即生效。 |
| `LOOMY_STRATEGY` | `balance` / `round_robin` / `lru` |

### 给网关加把锁
Expand All @@ -203,7 +206,7 @@ Key 存在浏览器 localStorage 里。
```

客户端带 `Authorization: Bearer sk-local-whatever` 或 `x-api-key: sk-local-whatever`。
`/health` 始终公开,方便探活。
面板登录页填的也是这把 Key。`/health` 始终公开,方便探活。

## Docker

Expand Down Expand Up @@ -321,11 +324,13 @@ docker compose logs -f

默认只监听 `127.0.0.1`,只有本机能访问。要在局域网/公网共享:

1. **先设 API Key**。不设的话,谁能连上这个端口就能花你账号的积分:
1. **先设 API Key**。不设的话,谁能连上这个端口就能花你账号的积分,面板也没有登录页:

```json
{ "api_keys": ["sk-换成一串又长又随机的字符串"] }
```

设好之后打开站点会先进入登录页。Key 只用来核对,不会留在浏览器里。
2. 再设 `LOOMY_HOST=0.0.0.0`(或 config.json 里 `"host": "0.0.0.0"`)。
3. 公网的话,前面挂一个带 TLS 的反代。Caddy 示例:

Expand Down
4 changes: 2 additions & 2 deletions config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
"access_key_secret": "",

"loomy_version": "0.9.38",
"_proxy": "empty = direct connection (recommended for these domestic endpoints)",
"_proxy": "empty = direct. socks5://, http://, or https://user:pass@host:port. SOCKS5 resolves names at the proxy. Editable from the panel.",
"proxy": "",

"_api_keys": "empty list = the gateway needs no key. Set e.g. [\"sk-abc\"] to require Bearer/x-api-key.",
"_api_keys": "empty list = no auth (fine on localhost). Set e.g. [\"sk-abc\"] to require Bearer/x-api-key on the model API and a login page on /panel. The panel session cookie is not accepted on /v1.",
"api_keys": [],

"default_model": "deepseek-v4-flash-0731",
Expand Down
5 changes: 4 additions & 1 deletion loomy2api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"access_key_id": "", # empty → use the client-shipped constant
"access_key_secret": "",
"loomy_version": C.DEFAULT_LOOMY_VERSION,
"proxy": "", # "" = direct; e.g. http://127.0.0.1:7877
"proxy": "", # "" = direct; http:// https:// or socks5://host:port

# gateway -------------------------------------------------------------
"api_keys": [], # [] = no auth; otherwise Bearer / x-api-key
Expand Down Expand Up @@ -132,4 +132,7 @@ def load_config(path: str | os.PathLike | None = None) -> Config:
if value:
cfg[cfg_key] = _coerce(cfg, cfg_key, value)

# Remember where to write panel edits back. Missing file is fine.
cfg.config_path = config_path
cfg.proxy_from_env = bool(os.environ.get("LOOMY_PROXY"))
return cfg
Loading