From 6ba07dd23b6af899decd8ae1fc9de73bb54209c9 Mon Sep 17 00:00:00 2001 From: Lumpiasty Date: Fri, 12 Jun 2026 02:09:51 +0200 Subject: [PATCH] State dir clarifications --- .woodpecker/pr-build.yaml | 11 +++++++++++ .woodpecker/release-tag.yaml | 7 +++++++ docs/DESIGN.md | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/.woodpecker/pr-build.yaml b/.woodpecker/pr-build.yaml index 343c704..13c1d8b 100644 --- a/.woodpecker/pr-build.yaml +++ b/.woodpecker/pr-build.yaml @@ -9,10 +9,21 @@ # Reports pass/fail status back to Gitea, so it shows up as a required check on # the PR. +# Doc-only changes can't affect the image, so they don't trigger the build. +# NOTE: if Gitea is ever configured to REQUIRE this check for merging, a +# doc-only PR will have no check at all — exempt such PRs or merge manually. +# Renovate PRs always touch the Dockerfile or pipeline files, so the +# automerge gate is unaffected by these exclusions. when: - event: pull_request + path: + exclude: &doc_paths + - '**/*.md' + - 'docs/**' - event: push branch: main + path: + exclude: *doc_paths steps: - name: Build all arches (no push) diff --git a/.woodpecker/release-tag.yaml b/.woodpecker/release-tag.yaml index 6ddcc65..aa50efc 100644 --- a/.woodpecker/release-tag.yaml +++ b/.woodpecker/release-tag.yaml @@ -13,9 +13,16 @@ # unchanged, so no tag is created and nothing is released — they ride along # with the next Tailscale bump or manual tag. +# Skipped for doc-only pushes: TAILSCALE_VERSION lives in the Dockerfile, so a +# push that doesn't touch non-doc files can never introduce a new version to +# tag (the job would just no-op after spinning up OpenBao + git containers). when: - event: push branch: main + path: + exclude: + - '**/*.md' + - 'docs/**' steps: - name: Get git token from OpenBao diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 1921797..5c0b2e3 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -294,6 +294,22 @@ Only the small, rarely-written state file touches flash; the socket dir is tmpfs. The netmap is held in memory only — see [Why netmap disk-caching is removed](#why-netmap-disk-caching-is-removed). +### What lives in the state dir + +| File | Purpose | Write frequency | +|---|---|---| +| `tailscaled.state` | Node identity, auth keys, prefs | On auth / key rotation / prefs change | +| `derpmap.cached.json` | Cached DERP relay server list for **bootstrap DNS**: at cold start with broken/unavailable DNS, tailscaled asks DERP servers to resolve the control plane. The binary ships a static DERP list, but it goes stale; this cache keeps the current one. | Once at first auth, then **only when Tailscale's relay infrastructure changes** (a few times a year). `dnsfallback.UpdateCache` has a deep-equal guard and skips the write when the DERP map is unchanged — netmap churn never touches it. | + +`derpmap.cached.json` is intentionally **kept** despite the flash-wear policy: +the policy targets *frequent* writes (netmap deltas, logs), not one-shot +caches. On a router this cache is genuinely useful — after a power outage the +device may boot with WAN up but upstream DNS broken, exactly the case where a +fresh DERP list lets the node reach the control plane anyway. With +`cachenetmap` omitted, this file and `tailscaled.state` are the only cold-start +resilience the node has. (There is no `ts_omit_*` tag for it; it is written +only because `--statedir` is set.) + ## Flash wear protection Several measures are in place to avoid wearing out internal flash: -- 2.52.0