claude agent, operated by james@keymail.devoperated by james@keymail.devsession 14c51d07 · claude-code/2.1.273 · hal
Problem
On every deployment, carlos domains attach refuses any name under PLATFORM_APPS_DOMAIN and any name under the console's own hostname. The error is "that hostname is platform-managed". The rule comes from deniedDomains() in internal/console/apidomains.go (#151).
The rule is correct for a platform that hosts apps for other people, such as the flagship or carloku. There, the apps domain belongs to the operator, and a claim under it would let one tenant take another tenant's address.
On a self-hosted deployment, one person usually owns the whole zone. For example, the console is at carlos.example.com and the apps are at <app>.<sqid>.carlos.example.com. The rule then refuses ordinary names such as blog.carlos.example.com. Almost every self-hoster meets this. The deployments that need the rule should opt in to it. It should not be the default.
Change (branch reserve-platform-domains-opt-in)
New console setting: CONSOLE_RESERVE_PLATFORM_DOMAINS (Config.ReservePlatformDomains). Unset means false. A value that is not a boolean stops the console at boot.
With the setting: the door refuses the same names as before: every name under the apps domain, under the origin host, and under the redirect hosts.
Every deployment still refuses: - the console's origin host and its CONSOLE_REDIRECT_HOSTS, by exact name. An alias on one of these names points the console's own address at an app. That is a self-harm guard, not a tenant guard. - CONSOLE_DENY_DOMAINS and CARLOS_TUNNEL_HOST, with their subtrees. The operator listed these names on purpose. - a hostname that another app's route already holds (deploymentRouteTaken, which did not change).
Both doors (the API door and the console form's attachDomain) now call one method, hostDenied.
Tests: the reserved test set now runs with the setting on. It also covers the apps-domain apex and names under the origin host. New tests cover the unreserved default through both doors. I ran the new tests against the old behaviour and saw them fail.
Docs: README.md (config surface) and docs/site/cli.md (carlos domains).
⚠️ Rollout
Before any shared-platform console (the flagship, carloku) runs this build, add CONSOLE_RESERVE_PLATFORM_DOMAINS=true to its environment. Without it, a tenant can claim an unused name under oncarlos.com. Names that routes already hold stay protected, but names not yet minted and canary hosts do not. The env files for those deployments are in platform-infrastructure, which this branch does not change.
Notes
Without the setting, a member can also claim the apps-domain apex, and names that are shaped like platform URLs but that no route holds yet. On a single-owner deployment that is intended. A self-hosted operator who invites members they do not trust should set the flag.
Not changed: the sibling-apex check in carlos instances create (apiinstances.go), which is a separate door.
Gate: go build, go vet and gofmt are clean. make test has one failure on my VPS, internal/activatorTestExecBackendStartWithNilCacheStillBindsControlSocket. That package does not import the console, so this change cannot cause it. It fails the same way when run alone. The amadan CI run will show whether it also fails there.
claude agent, operated by james@keymail.devoperated by james@keymail.devsession 14c51d07 · claude-code/2.1.273 · hal
Merged to main as e6773f5, after the branch CI passed on b07c406: gate, cross and minio-contract all green.
Before merging, I merged main into the branch. Main had gained the short-alias delegation (CONSOLE_APPS_DOMAIN_ALIAS_ACCOUNTS, e36cdb6a), which rewrote the same deny check. How the two combine:
domainHostDenied is now the one check both attach paths use. On every deployment it refuses the console's own hostnames by exact name, plus the steering host and CONSOLE_DENY_DOMAINS.
The apps domain, and every name under the console's hostnames, is refused only when CONSOLE_RESERVE_PLATFORM_DOMAINS is set. The alias delegation, and its limits on wildcard, catchall and first-route attaches, also apply only in that mode.
AGENTS.md records the new rule.
Rollout: before a shared-platform console (the flagship, carloku, Tito) runs this build, add CONSOLE_RESERVE_PLATFORM_DOMAINS=true to its environment. On Tito this is also required for the bap alias delegation to keep its limits.
claude agent, operated by james@keymail.devoperated by james@keymail.devsession 14c51d07 · claude-code/2.1.273 · hal
Verified in production on a self-hosted deployment (carlos.exciting.io, both binaries at e6773f5, no CONSOLE_RESERVE_PLATFORM_DOMAINS set):
carlos domains attach --app pitch pitch.carlos.exciting.io was accepted, and the host serves the static site. That name is one label under the apps domain AND under the console's own hostname, which is exactly what the previous build (2642034) refused with "that hostname is platform-managed".
One deployment note for anyone upgrading a self-hosted console across this range: a console with CARLOS_STORE_BACKEND set now exits at boot unless CARLOS_STORE_USER_BOUNDARY is also set. That is unrelated to this change, but it is what made the first install of the new console fail here. A deployment that was never built from infra/modules/region-host has to create that IAM policy by hand.