Skip to content

#8 docs: Tailscale DNS proven across a hard reset - #11

Merged
gregoryfoster merged 3 commits into
mainfrom
8-hard-reset
Oct 1, 2026
Merged

gregoryfoster merged 3 commits into
mainfrom
8-hard-reset

Conversation

@gregoryfoster

@gregoryfoster gregoryfoster commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Refs #8. Follows #10, which listed the hard-reset path as untested.

What the hard reset showed

This was ssh exe.dev restart co-processor on 2026-10-01; the boot started at 18:46:41Z. The previous boot's journal stops at 18:45:01 with no SIGTERM and no tailscaled --cleanup, so the stop hook didn't run. Two one-shot units recorded the boot: one snapshotted the files before tailscaled started, the other ran after it. Both are now removed; copies and the log are in /var/backups/processor/8/.

  • Before tailscaled started (1.98 s), /etc/resolv.conf already held exe.dev's nameserver 169.254.169.254. It had been rewritten 1.5 s into boot (mtime at 1.534 s), as exe-init started its guest daemon (exe-init guestd, 1.53 s). guestd runs in PID 1's init.scope, not as a service, so this was before exe-init exec'd systemd; journald came up at 1.84 s. tailscaled's file had not survived the boot. /etc/hosts, which already matched, wasn't touched. Tailscale's old backup was still present.
  • tailscaled started at 2.1 s, at -950, with CorpDNS: true. It deleted the leftover backup. It took the file over at +1.60 s (exact, from the mtime), backing up exe.dev's fresh copy.
  • Lookups: public names resolved on the probe's first try (+0.8 s); broker and index by +1.67 s. The probe polled every 0.25 s, so these are upper bounds.
  • After the boot: the journal has no name-resolution error, no units failed, and tests/test_tailscaled.py passes on the node (18 of 18).

In DEPLOYMENT.md

  • "How it works here" states the two observations. After the hard reset, exe.dev's init replaced the tailscaled file it found. After the graceful reboot, when the file already matched, it left it alone, as it has /etc/hosts at both boots.
  • "At boot":
    • the hard-reset measurement replaces the "untested" paragraph;
    • the probe is described as two units, and how to arm it again;
    • a note that on both paths tailnet names wait for tailscaled's takeover (1.5–1.6 s after it starts) while public names don't.

Also on #5: the tailnet-policy item is ticked, verified from here. index and index.taild0fb76.ts.net resolve, 6333 and 11434 accept connections, Qdrant's TLS certificate verifies for the full name, and Ollama answers.

Review

CR --fix, findings 13–14, one commit each:

  • CR 13: the evidence that exe-init acted before systemd is now guestd's start and its init.scope cgroup. Systemd's first journal line was a weak stand-in, since PID 1 runs --log-target=syslog.
  • CR 14: "writes it again at boot" became what was observed: rewritten when it differed, left alone when it matched.

"tailscaled deleted the backup" was checked against tailscale 1.102.4's net/dns/direct.go. restoreBackup drops a backup when a non-Tailscale resolv.conf is in place, and the direct manager's Close() calls it: the boot shows two "using direct mode" lines, 90 ms apart.

Gate

uv run pytest: 215 passed. ruff check, ruff format --check and uv lock --locked are clean, and the scratch Redis is clean.

🤖 Generated with Claude Code

gregoryfoster and others added 3 commits October 1, 2026 18:55
…ailscaled's file at boot

A hard reset (exe.dev restart) on 2026-10-01 skipped tailscaled's stop hook.
exe.dev's init still replaced tailscaled's file 1.5 s into boot, before
systemd. tailscaled deleted the stale backup and took the file over at
+1.60 s. The graceful reboot, where the file already matched, left it alone,
so the runbook states both observations and drops the "untested" paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d init.scope, not systemd's first journal line

PID 1 runs --log-target=syslog, so systemd's first journal line (1.91 s) is
no measure of its start. The rewrite (1.534 s) coincides with exe-init
guestd's start (1.53 s), which lives in init.scope, not a service.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t it when it matched, not 'writes it again at boot'

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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