外观
让前端指向另一个控制面
四个站默认都连生产。指向本地后端或另一套部署时,各站的做法不同——因为它们的托管 形态不同。
配置项全表见 reference/configuration.md。
控制台
方式一:登录页直接填(最快,不用改文件)
登录页切到「API Token」页签,「控制服务器地址」输入框里填新地址,连同 admin token 一起提交。该地址存进 localStorage(dn42.admin.apiBase),优先于构建期缺省。
同一份静态产物因此能指向不同机群。「管理员账号」方式固定连默认控制面,不暴露覆盖。
⚠️ 生产环境下这个覆盖受 CSP 约束:只有
apps/control/worker/index.js的connect-src里列出的主机可达。指向一个新的控制面必须同时改那份允许清单并重新部署, 否则浏览器会静默拦掉请求。本地开发服务器不发 CSP,不受此限。
方式二:构建期缺省
bash
# apps/control/.env.local
VITE_CONTROL_API=http://127.0.0.1:8000对等门户
bash
# apps/peering/.env.local
VITE_PEERING_API=http://127.0.0.1:8000门户没有运行时覆盖入口。
门户的登录闭环还需要两件事,否则只能看不能登:
- 后端
[portal] frontend_base_url指向本地前端(http://localhost:5174) ——授权完成后要跳回来; - 本地来源在控制面 CORS 白名单内。
授权界面
它与认证服务同源部署,所以本地开发不用切基址:vite.config.ts 把 /api 反代到 https://auth.natlan.io,布局与线上一致,前端代码始终用相对路径、也没有 CORS。
要指向另一套认证服务部署:
bash
# apps/auth/.env.local
VITE_AUTH_API=https://auth.example.org⚠️ 这样一来请求就变成跨源了——目标部署必须放行本地来源,且同源假设不再成立。 只在确实需要对接另一套后端时用。
首页
首页的 API 地址是硬编码的 https://api.natlan.io,出现在三处:
| 位置 | 用途 |
|---|---|
apps/home/index.html 的 <head> 预取与内联脚本 | 统计条带与地图的实时刷新 |
apps/home/fleet-widget/src/main.ts | fleet 岛的数据源 |
apps/home/bake.js | 烘焙快照的来源 |
首页是纯静态页、没有构建期环境变量层,指向别处需要改这三处。这是有意的取舍—— 它只有一个生产部署。
后端侧的 CORS
控制台与门户是跨源直连后端的,因此后端必须把前端来源加入 CORS 白名单:
| 后端实现 | 配置项 |
|---|---|
| TypeScript 控制器 | CORS_ORIGINS var |
| Python 控制器 | DN42_CONTROL_CORS_ORIGINS |
本地开发要加的是 http://127.0.0.1:5173(控制台)与 http://localhost:5174(门户)。 注意 127.0.0.1 与 localhost 是不同的来源,按实际使用的那个加。
授权界面不需要 CORS——它同源。
人机验证的白名单
控制台登录页与授权界面都会渲染 Cap 控件。Cap 实例(challenges.natlan.io)的 CORS 白名单需要包含所有消费方来源,本地开发来源也在内,否则控件取不到题。
验证连通性
bash
# 控制面是否可达、token 是否有效
curl -H "Authorization: Bearer <token>" http://127.0.0.1:8000/control/v1/ui/session
# CORS 预检是否通过(换成实际的前端来源)
curl -si -X OPTIONS http://127.0.0.1:8000/control/v1/ui/session \
-H "Origin: http://127.0.0.1:5173" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: authorization" | grep -i access-control第二条应当回出 Access-Control-Allow-Origin 与允许的方法/头。