mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-13 11:07:18 +00:00
feat(webui): 外部入口 base_url 配置 —— 穿透场景下链接不再靠猜
用户指出 webui 实际是经 https://homeagent.jianfgit.xyz/ 穿透出去的, 应当支持配置 base URL。实测确认了这个诉求的正当性。 ## 实测发现的约束(决定方案) 1. **子域形态在外部不可用**:`*.homeagent.jianfgit.xyz` 泛解析存在, 但外层只给 `*.jianfgit.xyz` 通配证书 —— 该证书**不匹配三级子域**, 实测 `huawei-smarthome.homeagent.jianfgit.xyz` 外部握手失败(HTTP 000)。 外层只放行 `homeagent.jianfgit.xyz` 这一个 Host。 2. **路径挂载形态外部可用**:实测 `https://homeagent.jianfgit.xyz/api/v1/device/online` → 200。 所以「一个外部 Host + 路径挂载」是这条链路的正解,且已经工作。 3. 外层 nginx/WAF 会带 `X-Forwarded-Proto: https` 与 `X-Forwarded-Host`, 因此即使不配置也能推出正确链接;配 base_url 则是显式兜底。 ## 新增设置项 base_url 三级优先解析「对外入口」(resolveEntry): 1. **配置项 base_url** —— 外部入口是部署事实,不该靠请求猜。 经多层网关时请求可能带内网 Host,按它推导会拼出用户点不开的链接。 2. **X-Forwarded-Proto / X-Forwarded-Host** —— 反代层给权威信息时可靠。 3. **请求自身** —— 直连时的正确来源。 base_url 的主机名同时用作**子域反代的基域名**:入口是 homeagent.example.com 时,插件服务自然是 <标签>.homeagent.example.com。 服务清单另增 entry_url 字段,直接给出「外部入口是什么」,便于前端与排错。 ## 生效点 - `/api/v1/proxy/services`:url / url_portal / base_domain / entry_url - `/api/v1/device/gateway`:url / url_portal / http_url / host - 两处原先各自推导 portalHost,现统一走 resolveEntry,避免再次漂移 ## 部署后实测(生产,经真实外部入口) entry_url: https://homeagent.jianfgit.xyz base_domain: homeagent.jianfgit.xyz remotedevice | https://devices.homeagent.jianfgit.xyz | https://homeagent.jianfgit.xyz/api/v1/device/ ← 外部可点 huawei_smarthome| https://huawei-smarthome.homeagent.jianfgit.xyz 发现端点(外部视角): url_portal = wss://homeagent.jianfgit.xyz/api/v1/device/ws ← 外部可连 ## 判据 +3 条:TestBaseURLOverridesRequestDerived(内网 Host 场景下必须用 base_url)、 TestEntryPrefersForwardedHeaders(XFF 优先于请求自身)、 TestBaseURLTolerant(尾斜杠/空格容错 —— 手填配置最常见的两种手误)。 另更新一条旧判据的期望值:外部入口是 portal.example.com 时,子域基名应取 **实际入口**而非本机配置的 localhost(后者对远程用户无意义)。
This commit is contained in:
@ -235,7 +235,11 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
// 基域名:默认 localhost ⇒ <标签>.localhost:<端口> 开箱即用(RFC 6761 强制
|
||||
// 解析到 loopback,无需 DNS/证书/hosts)。远程访问时改成本机可达的域名,
|
||||
// 如 webui.example.com ⇒ <标签>.webui.example.com。
|
||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "base_domain", Default: "localhost", Type: "string", DisplayName: "反代基域名", Description: "插件服务反代的基域名。默认 localhost,此时 <插件标签>.localhost:<端口> 直接可用;远程访问填如 webui.example.com", Category: "webui"})
|
||||
// 外部入口 base URL:经 frp/nginx 穿透时,请求 Host 往往是内网地址或
|
||||
// 缺少协议信息,而生成给用户的链接必须是**外部可点的**。填这里即覆盖。
|
||||
// 例:https://homeagent.example.com —— 生成的链接一律用它做协议+主机。
|
||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "base_url", Default: "", Type: "string", DisplayName: "外部入口 Base URL", Description: "经反代/穿透暴露给外部的完整入口地址(含协议),如 https://homeagent.example.com。留空则按请求推导(直连时正确;经多层网关时可能拼错)。填了它,所有生成的外部链接都用它", Category: "webui"})
|
||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "base_domain", Default: "localhost", Type: "string", DisplayName: "反代基域名", Description: "插件服务按子域反代时用的基域名(如 webui.example.com 则 <插件标签>.webui.example.com)。默认 localhost 只对本机浏览器有效。若外层未放行子域,请改用手填反代条目或路径挂载", Category: "webui"})
|
||||
// 手填反代条目(自动发现之外的补充):每行 `<标签> <上游地址> [ws] [auth=none]`
|
||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "proxy_routes", Default: "", Type: "text", DisplayName: "手填反代条目", Description: "每行一条:<子域标签> <上游地址> [ws] [auth=none|homeagent]。插件的 proxies 声明会自动发现,这里只用于补充未声明/第三方服务。例:grafana 127.0.0.1:3000", Category: "webui"})
|
||||
s.Settings().RegisterDef(sdk.ConfigDef{Key: "device_gateway_enabled", Default: "false", Type: "bool", DisplayName: "设备网关反代", Description: "启用后 /api/v1/device/* 反代到 remotedevice 插件(默认关闭,避免硬耦合)", Category: "webui"})
|
||||
|
||||
Reference in New Issue
Block a user