Skip to content

relay: serve installers that install from the relay serving them - #5

Merged
Daily-AC merged 1 commit into
mainfrom
relay-serves-its-own-installer
Aug 31, 2026
Merged

relay: serve installers that install from the relay serving them#5
Daily-AC merged 1 commit into
mainfrom
relay-serves-its-own-installer

Conversation

@Daily-AC

Copy link
Copy Markdown
Owner

Problem

A relay's /install.sh and /install.ps1 exist for people who cannot reach the upstream release page. But the scripts it served were the ones the release build baked, whose fallback base is that same unreachable page — so the script downloaded fine and then stalled on its first request. The only way through was an exported WANCTL_RELAY that nothing surfaced to the user.

Second, installing from a mirror left wanctl update pointed back at the baked-in release page. ReleaseBase() read the environment and the build default but skipped the config file that every other setting resolves through, so there was no way to change it short of exporting a variable per invocation.

Change

  • The installers carry a RELAY_SELF marker that the serving relay fills in with its own WANCTL_PUBLIC_ORIGIN — the same shape /skills already uses for @WANCTL_RELAY@. The origin comes from the environment, never from request Host, and is rejected unless it is a plain http(s) origin free of characters that would stop being data once spliced into a shell or PowerShell script.
  • ReleaseBase() now resolves through Setting(), and release_base joins relay/portal/transport as a wanctl config set key.

selfhost/docker-compose.yml already passes RELAY_PUBLIC_ORIGIN as a required value, so self-hosted deployments get this with no configuration change.

Compatibility

A copy taken from the GitHub release page is unaffected — RELAY_SELF is empty there and the baked release base still wins. WANCTL_RELAY and WANCTL_DIST_BASE still override. An installer built before the marker existed is served untouched.

Verification

Base resolution, checked under dash on the rendered script:

relay-served (RELAY_SELF filled) release-page copy (empty)
no env https://relay.example/dl https://release.example/download
WANCTL_RELAY https://other.example/dl https://other.example/dl
WANCTL_DIST_BASE https://explicit.example/x

Plus new tests covering the rewrite for both installers, rejection of unsafe origins (quotes, backticks, $(…), newline, non-http scheme), and release_base persisting while still yielding to the environment. Full suite and go vet pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WCjgim6dZcTPZrhjk7fhkp

A relay's /install.sh and /install.ps1 existed for people who cannot reach
the upstream release page — but the scripts it served were the ones the
release build baked, whose fallback base is that same unreachable page. The
script downloaded fine and then stalled on its first request, and the only
way through was an exported WANCTL_RELAY that nothing told the user about.

The installers now carry a RELAY_SELF marker that the serving relay fills in
with its own WANCTL_PUBLIC_ORIGIN, exactly as /skills already does with
@WANCTL_RELAY@. The origin comes from the environment, never from request
Host, and is rejected unless it is a plain http(s) origin free of characters
that would stop being data once spliced into a shell or PowerShell script.
A copy taken from the GitHub release page is unaffected, and WANCTL_RELAY
and WANCTL_DIST_BASE still override.

Installing from a mirror left `wanctl update` pointed back at the baked-in
release page, with no way to change it short of exporting a variable per
invocation: ReleaseBase() read the environment and the build default but
skipped the config file every other setting resolves through. It now goes
through Setting(), and release_base joins relay/portal/transport as a key
`wanctl config set` accepts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCjgim6dZcTPZrhjk7fhkp
@Daily-AC
Daily-AC merged commit 6b52a30 into main Aug 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant