The owner caught me putting the archive on clupilot.cloud. That is the customer
zone, and looking into it turned up the same confusion already sitting in the
code — in the one place that matters most.
RegisterHostDns says "fsn-01.node.clupilot.com" in its own docblock. The
validation comment in Datacenters says it. ServicesTest writes it out verbatim.
The step itself built the name from config('provisioning.dns.zone') — the
CUSTOMER zone — so on this installation a host was actually called
fsn-01.node.clupilot.cloud. Three places asserting one thing and the code doing
another.
OfficialDomains explains why that matters and is worth not weakening: two
registrable domains by design, the company's for site, portal and console, the
instance zone for customer workloads. A Nextcloud is third-party software that
strangers sign into, and on the same registrable domain as the portal it shares
cookie scope with it. A host name in that zone does not break the separation,
but it puts it in question, and the next slip is more expensive.
So there is now a platform_zone, derived from APP_URL when unset, and
RegisterHostDns uses it.
My own archiveUrl was broken for a second reason. It fell back to url() when
APP_HOST is empty — and APP_HOST is empty on most installations, because empty
means "the portal answers on any hostname" and that is the default. Called from
the console, url() would have produced the CONSOLE hostname, and the line would
have 404'd on a machine that is not allowed to reach the admin area at all. It
takes the host from APP_URL now.
The script no longer guesses its own name. It used reverse DNS, then the tunnel
address, then a hard-coded clupilot.net — a third domain that appears nowhere
else in this project and was simply invented. PrepareBaseSystem has the same
invention. A guessed name does not stay guessed: it ends up in /etc/hostname, in
/etc/hosts, in every log line and in every certificate request the machine ever
makes. CluPilot knows the name because it just assigned it, so it passes --fqdn
and the script refuses without it. The value now also survives the reboot in the
arguments file, which it would not have.
The ACME contact moved to .com for the same reason it was wrong: the operator
does not live in the customer zone.
Open, and NOT decided here: the owner also wants the host to get a public DNS
record and a certificate on the .com name. RegisterHostDns deliberately writes
host names only into the tunnel's dnsmasq, and says why — publishing them hands
every scanner the internal subnet and roughly how many hosts sit behind it.
Nothing in the current design needs a public certificate for a host's own name;
Traefik serves customer domains, not this one. Reversing that is a security
decision and belongs to the owner, not to this commit.
1992 tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit shipped the guide AFTER the host was created. Its first two
steps happen at the provider — order the machine, boot the rescue system — and
whoever reads them there has the one-time code already in the clipboard with its
24-hour window running. The instructions were correct and in the wrong place,
which is its own kind of wrong.
Six steps now, not three, and the two provider ones are named rather than
assumed. They are marked "first" so the list does not read as something you can
start at the top of and work down: step 2 is half an hour of waiting, and doing
it inside a running code is exactly the mistake the page should prevent.
All six are visible the whole time, including the done ones and the ones still
to come. A guide that shows only the current step cannot answer "how much is
left", which is the question somebody has while a server they are paying for
sits in a rescue system.
It is on the hosts list too, collapsed. Somebody standing there may not have
ordered the machine yet — and that is step 1. Requiring them to click "add host"
to find out what the procedure is puts the answer behind the action it describes.
One component, two places, so the archive address in the instructions is the same
string the command line will carry. Two copies of that would drift, and the
difference would surface on a server that has already been paid for.
The step-4 command box moved into the guide rather than sitting beside it, so
after creating a host the whole procedure stays on screen. Somebody stuck at
step 5 should not be looking at a page that has become a single box.
1991 tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>