diff --git a/README.md b/README.md index d3eb3ed..ef7b859 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,14 @@ enables periodic unattended upgrades); writes an sshd hardening drop-in **verifies it took effect** via `sshd -T`; sets the system hostname; installs tailscale and joins your tailnet. +**`--hostname` converges both names.** On a box that has already joined, +`bootstrap` skips `tailscale up` (so a re-run needs no pre-auth key) — but it +still reconciles the **tailnet** hostname via `tailscale set --hostname`. Without +that, a box which joined under the wrong name — say `--hostname` was omitted, so +it defaulted to the *role* — stayed misnamed forever, and re-running rig, the +documented repair, could not fix it. A machine you deliberately renamed in the +admin console keeps that name; rig will not fight it. + > **Why the drop-in is `00-rig.conf` and not `99-`.** `sshd_config` is > **first-wins** — *"for each keyword, the first obtained value will be used"* > (`sshd_config(5)`) — and `Include` expands its glob in lexical order. Cloud diff --git a/commands/bootstrap.sh b/commands/bootstrap.sh index a76f4e5..22e171d 100755 --- a/commands/bootstrap.sh +++ b/commands/bootstrap.sh @@ -170,6 +170,26 @@ if ! command -v tailscale >/dev/null 2>&1; then fi if tailscale status >/dev/null 2>&1; then log "tailnet already joined; skipping tailscale up (no pre-auth key needed)" + # ...but skipping `tailscale up` also skipped --hostname, so the TAILNET name + # never converged: a box that joined under the wrong name (e.g. --hostname + # omitted, so it defaulted to the ROLE) stayed misnamed forever, and re-running + # rig — the documented repair — could not fix it. rig is convergent by + # contract; this was the one field that wasn't. `tailscale set` converges it + # without a re-auth or a pre-auth key. + # + # Safe by construction here: Tailscale ACLs cannot bind a rule's dst to a + # hostname (it must be a tag, an IP, or a `hosts` alias — which is exactly why + # acl.hujson pins coolify-box to an IP), so a rename cannot silently void a + # grant. It also will NOT clobber a deliberate rename: a machine renamed in the + # admin console keeps that name, and the device hostname no longer overrides it. + current_ts_name="$(tailscale status --peers=false 2>/dev/null | awk 'NR==1 {print $2}')" + if [ -n "$current_ts_name" ] && [ "$current_ts_name" != "$TS_HOSTNAME" ]; then + log "tailnet hostname is '${current_ts_name}', want '${TS_HOSTNAME}' — converging" + tailscale set --hostname="$TS_HOSTNAME" \ + || warn "tailscale set --hostname failed; rename '${current_ts_name}' -> '${TS_HOSTNAME}' in the admin console" + else + log "tailnet hostname already ${TS_HOSTNAME}" + fi else # env override, else prompt; never touches disk if [ -z "${TS_AUTHKEY:-}" ]; then