外观
配置参考
域名、API 基址、构建期变量、浏览器存储键的完整清单。事实源是各站的 src/lib/config.ts 与 vite.config.ts;本文与之保持一致。
1. 域名
| 主机名 | 承载 | 托管 |
|---|---|---|
natlan.io | 品牌首页 | Cloudflare Worker natlan-io-home |
console.natlan.io | 控制台 | Cloudflare Worker dn42-control-webui |
peering.natlan.io | 对等门户 | Cloudflare Worker dn42-peering-webui |
auth.natlan.io | OAuth 授权界面 + 认证服务 | 源站 nginx(同源) |
api.natlan.io | 控制服务器(当代 TS 控制器) | 源站 |
challenges.natlan.io | 自托管 Cap 人机验证实例 | 独立部署 |
四个 Worker 均已关闭 workers.dev 子域("workers_dev": false),只从自有域名对外。
历史控制面主机,仅出现在控制台的允许清单里,不再是任何默认值:
| 主机名 | 说明 |
|---|---|
legacy.api.natlan.io | Python 控制器 |
control-server.ngworks.org | 品牌化之前的别名 |
控制台不提供切换 UI,但当会话指向其中之一时,界面会把该地址标记为 legacy (isLegacyApiBase())。已登录会话保持登录时使用的基址,直到重新登录。
2. API 基址与前缀
控制服务器把三个服务并列在同一个基址下:
https://api.natlan.io/control/v1/… 控制面(控制台 + 门户)
https://api.natlan.io/auth/v1/… 认证服务(服务端到服务端)
https://api.natlan.io/registry/v1/… 注册表服务前端实际使用的四条路径:
| 消费方 | 基址 | 前缀 |
|---|---|---|
| control | VITE_CONTROL_API ?? https://api.natlan.io | /control/v1/ui/*、/control/v1/admin/*、/control/v1/auth/* |
| peering | VITE_PEERING_API ?? https://api.natlan.io | /control/v1/autopeering/*(另直连 /control/v1/public/fleet) |
| home | 硬编码 https://api.natlan.io | /control/v1/public/{fleet,map} |
| auth | VITE_AUTH_API ?? ''(同源) | /api/v1/* |
授权页的前缀与其余三站不同,因为它与认证服务同源部署,走的是认证服务在根上的 那一处挂载。理由见 internals/auth-hosting.md。
⚠️ 旧的
/api/v1/*前缀在api.natlan.io上已全线 404。任何仍写着这个前缀的 控制面/门户/首页代码都是失效的。
3. 构建期环境变量
三个变量都在构建时烘焙进产物,运行时不可改(控制台的登录页覆盖除外,见第 4 节)。
| 变量 | 站 | 缺省 | 用途 |
|---|---|---|---|
VITE_CONTROL_API | control | https://api.natlan.io | 控制服务器基址 |
VITE_PEERING_API | peering | https://api.natlan.io | 控制服务器基址 |
VITE_AUTH_API | auth | ''(同源) | 指向另一套认证服务部署 |
本地开发写进对应 app 目录下的 .env.local,例如:
bash
# apps/peering/.env.local
VITE_PEERING_API=http://127.0.0.1:8000授权页不用环境变量做本地开发:它的 vite.config.ts 把 /api 反代到 https://auth.natlan.io,与线上 nginx 的同源布局一致,因此前端代码始终用相对路径、 本地也没有 CORS。
其余可选变量:截图工具链读 SHOT_BASE / SHOT_API / SHOT_LOCALE 与 DN42_ADMIN_TOKEN,见 guides/capture-screenshots.md。
4. 运行时覆盖(仅控制台)
控制台登录页的「API Token」方式带一个控制服务器地址输入框,填写后存入 localStorage,优先于构建期缺省。同一份静态产物因此能指向不同机群。
「管理员账号」方式固定连默认控制面,不暴露地址覆盖。
⚠️ 这个覆盖受 CSP 的 connect-src 约束:只有 apps/control/worker/index.js 里列出的 主机可达。指向新控制面需要同时改那份允许清单,见 csp.md。
5. 浏览器存储键
控制台
| 键 | 存储 | 内容 |
|---|---|---|
dn42.admin.token | localStorage | 账号会话令牌或 admin token |
dn42.admin.apiBase | localStorage | 运行时覆盖的控制服务器地址 |
dn42.admin.loginMethod | localStorage | 上次成功的登录方式(admin / token),决定默认页签 |
dn42.theme | localStorage | light / dark / system |
dn42.locale | localStorage | en / zh / zh-Hant / ja |
dn42.autorefresh | localStorage | 自动刷新总开关(0 = 关) |
dn42.sidebar.collapsed | localStorage | 侧栏折叠态 |
对等门户
| 键 | 存储 | 内容 |
|---|---|---|
natlan.peering.session | sessionStorage | 门户会话令牌 |
natlan.peering.theme | localStorage | 主题偏好 |
natlan.peering.locale | localStorage | en / zh |
natlan.peering.sidebar.collapsed | localStorage | 侧栏折叠态 |
授权界面
| 键 | 存储 | 内容 |
|---|---|---|
dn42.auth.session | sessionStorage | 身份会话 JWT |
dn42.auth.lastAsn | localStorage | 上次验证成功的 ASN,用于下次自动 passkey 尝试 |
dn42.auth.lang | localStorage | 语言偏好 |
两处 sessionStorage 的选择是安全红线,不是风格:会话令牌是身份凭据,必须随标签页 消亡,不进 localStorage、不进 cookie、不进 URL。dn42.auth.lastAsn 反过来必须比 标签页活得久,而 ASN 是半公开的 registry 数据、不是凭据,因此那条红线对它不适用。
控制台的 dn42.admin.token 在 localStorage,是另一套权衡:它是长驻运维控制台, 每次开标签页重新登录不可接受,且没有第三方内容能进入它的来源。
6. 第三方端点
| 端点 | 用途 |
|---|---|
https://challenges.natlan.io/1018704021/ | Cap 控件的出题/兑换端点。site key 烘焙在路径里且按设计公开;secret 只在服务端 |
https://static.cloudflareinsights.com | Cloudflare Web Analytics beacon,边缘注入 |
Cap 实例的 CORS 白名单需包含所有消费方来源:console.natlan.io、auth.natlan.io 及本地开发来源。