fix(enroll): rewrite loopback server host to the browser-facing host #35

Merged
David merged 1 commit from fix/enroll-loopback-host-vapp-29 into main 2026-06-14 00:01:43 +02:00
Owner

The "Enroll a new device" dialog embedded localhost in the .msh MeshServer=/ServerURL= lines, the agent download URL, and the install snippet whenever vervain-server had no public host configured (its cert default is the literal "localhost"), so a remote Linux device was told to curl an address it can never reach. vervain-server only ever sees the internal proxy hop as its request Host, so the browser-facing host is known only to the vervain-apps SSR layer.

In the get_mesh_install server fn, after parsing the MeshServer host, detect whether it is loopback (localhost, 127.0.0.0/8, or ::1; port-insensitive). A non-loopback host means vervain-server has a real external_base_url/cert and stays authoritative, so split-DNS / reverse-proxy deployments are untouched. A loopback host is rewritten to the host the operator reached the app on, sourced from the incoming request (first X-Forwarded-Host value, then Host). The rewrite swaps only the authority in both the .msh MeshServer= line and the derived server_url, preserving scheme (wss/ws, https/http) and path (/api/v1/agent, /meshagents/); augment_msh_for_agent then derives ServerURL= from the rewritten line so every artifact agrees on the same host. When the host is loopback and no Host/X-Forwarded-Host is available, MeshInstall carries a non-fatal hint that the dialog renders, telling the operator to configure external_base_url rather than silently shipping localhost.

Unit tests cover loopback detection (localhost / 127.x / ::1, with and without ports and IPv6 brackets), config-wins (non-loopback preserved), authority replacement (scheme/path preserved), and the rewrite helper keeping the .msh line and server_url in sync.

#VAPP-29

The "Enroll a new device" dialog embedded localhost in the .msh MeshServer=/ServerURL= lines, the agent download URL, and the install snippet whenever vervain-server had no public host configured (its cert default is the literal "localhost"), so a remote Linux device was told to curl an address it can never reach. vervain-server only ever sees the internal proxy hop as its request Host, so the browser-facing host is known only to the vervain-apps SSR layer. In the get_mesh_install server fn, after parsing the MeshServer host, detect whether it is loopback (localhost, 127.0.0.0/8, or ::1; port-insensitive). A non-loopback host means vervain-server has a real external_base_url/cert and stays authoritative, so split-DNS / reverse-proxy deployments are untouched. A loopback host is rewritten to the host the operator reached the app on, sourced from the incoming request (first X-Forwarded-Host value, then Host). The rewrite swaps only the authority in both the .msh MeshServer= line and the derived server_url, preserving scheme (wss/ws, https/http) and path (/api/v1/agent, /meshagents/<id>); augment_msh_for_agent then derives ServerURL= from the rewritten line so every artifact agrees on the same host. When the host is loopback and no Host/X-Forwarded-Host is available, MeshInstall carries a non-fatal hint that the dialog renders, telling the operator to configure external_base_url rather than silently shipping localhost. Unit tests cover loopback detection (localhost / 127.x / ::1, with and without ports and IPv6 brackets), config-wins (non-loopback preserved), authority replacement (scheme/path preserved), and the rewrite helper keeping the .msh line and server_url in sync. #VAPP-29
fix(enroll): rewrite loopback server host to the browser-facing host
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 1m19s
Create release / Create release from merged PR (pull_request) Has been skipped
9f076455dc
The "Enroll a new device" dialog embedded localhost in the .msh MeshServer=/ServerURL= lines, the agent download URL, and the install snippet whenever vervain-server had no public host configured (its cert default is the literal "localhost"), so a remote Linux device was told to curl an address it can never reach. vervain-server only ever sees the internal proxy hop as its request Host, so the browser-facing host is known only to the vervain-apps SSR layer.

In the get_mesh_install server fn, after parsing the MeshServer host, detect whether it is loopback (localhost, 127.0.0.0/8, or ::1; port-insensitive). A non-loopback host means vervain-server has a real external_base_url/cert and stays authoritative, so split-DNS / reverse-proxy deployments are untouched. A loopback host is rewritten to the host the operator reached the app on, sourced from the incoming request (first X-Forwarded-Host value, then Host). The rewrite swaps only the authority in both the .msh MeshServer= line and the derived server_url, preserving scheme (wss/ws, https/http) and path (/api/v1/agent, /meshagents/<id>); augment_msh_for_agent then derives ServerURL= from the rewritten line so every artifact agrees on the same host. When the host is loopback and no Host/X-Forwarded-Host is available, MeshInstall carries a non-fatal hint that the dialog renders, telling the operator to configure external_base_url rather than silently shipping localhost.

Unit tests cover loopback detection (localhost / 127.x / ::1, with and without ports and IPv6 brackets), config-wins (non-loopback preserved), authority replacement (scheme/path preserved), and the rewrite helper keeping the .msh line and server_url in sync.

#VAPP-29
David merged commit 5fd125b198 into main 2026-06-14 00:01:43 +02:00
David deleted branch fix/enroll-loopback-host-vapp-29 2026-06-14 00:01:43 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-apps!35
No description provided.