From f33e7474b099f225c6272f23a42a5a3468f986b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 13 Aug 2026 03:03:45 +0000 Subject: [PATCH] default PUBLIC_URL to the tailnet address, not localhost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit localhost is wrong on a machine with a tailnet, and quietly so: it works from the machine itself and nowhere else, so the mistake surfaces on the first phone rather than during setup. And PUBLIC_URL is not decoration — gen:index bakes it into the page's OpenGraph tags, the task API hands it to scripts as OFFICER_API_HOST, and the CalDAV profile builder refuses without it. The tailnet is where Officer is actually reached, and it is the perimeter the whole security model rests on now that origin checking is gone. Its address is the honest default. Prefers the MagicDNS name over the raw 100.x address — both work, but the name survives a node being re-registered and is something a person can type. Falls back to localhost with no tailnet, which is right rather than merely tolerable: a machine with no private network has no better address to guess. Suggests http://officer-dev.ts.pastilhas.dev:9000 on this machine. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/setup/officer-setup.sh | 6 +++- scripts/setup/officer-setup/lib/env.sh | 40 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/scripts/setup/officer-setup.sh b/scripts/setup/officer-setup.sh index 8b7b461c..17ba54c1 100755 --- a/scripts/setup/officer-setup.sh +++ b/scripts/setup/officer-setup.sh @@ -505,7 +505,11 @@ if ! skip; then echo " it: the OpenGraph tags baked into the page by 'bun gen:index', the" echo " host the task API hands to scripts, and the CalDAV profile an iPhone" echo " installs — that last one requires https." - ask_required ENV_PUBLIC_URL "Public URL" "${ENV_PUBLIC_URL:-http://localhost:${ENV_PORT}}" + echo "" + echo " Defaulting to this machine's tailnet address, not localhost: the" + echo " tailnet is where Officer is actually reached from, and localhost" + echo " works from here and nowhere else." + ask_required ENV_PUBLIC_URL "Public URL" "${ENV_PUBLIC_URL:-$(default_public_url "$ENV_PORT")}" echo "" echo " to write:" diff --git a/scripts/setup/officer-setup/lib/env.sh b/scripts/setup/officer-setup/lib/env.sh index 49a7df24..80c98411 100644 --- a/scripts/setup/officer-setup/lib/env.sh +++ b/scripts/setup/officer-setup/lib/env.sh @@ -76,3 +76,43 @@ ENVF chmod 600 "$dest" return 0 } + +# ----------------------------------------------------------------------------- +# A sensible default for PUBLIC_URL +# ----------------------------------------------------------------------------- +# +# localhost is the wrong default on a machine with a tailnet, and quietly so: +# it works from the machine itself and from nowhere else, so the mistake shows up +# on the first phone, not during setup. +# +# The tailnet is where Officer is actually reached — it is the perimeter the +# whole security model rests on — so its address is the honest default. +# +# MagicDNS name preferred over the raw 100.x address. Both work, but the name +# survives the node being re-registered and reads as something a person can type, +# and PUBLIC_URL ends up baked into the page's OpenGraph tags by `bun gen:index`. +# +# Falls back to localhost when there is no tailnet, which is correct rather than +# merely tolerable: a machine with no private network has no other address that +# is any better a guess. +tailnet_hostname() { + local dns ip + dns="$(tailscale status --json 2>/dev/null | grep -oP '"DNSName":\s*"\K[^"]+' | head -1)" + dns="${dns%.}" + if [[ -n "$dns" ]]; then + echo "$dns" + return 0 + fi + ip="$(tailscale ip -4 2>/dev/null | head -1)" + [[ -n "$ip" ]] && echo "$ip" +} + +default_public_url() { + local host + host="$(tailnet_hostname)" + if [[ -n "$host" ]]; then + echo "http://${host}:${1}" + else + echo "http://localhost:${1}" + fi +}