diff --git a/engine/lint-report.md b/engine/lint-report.md index 378cc8e..6278f68 100644 --- a/engine/lint-report.md +++ b/engine/lint-report.md @@ -1,6 +1,6 @@ # Vault Lint Report -Generated: 2026-06-22T12:00:09Z | Docs scanned: 94 | Elapsed: 0.0s +Generated: 2026-06-22T18:00:09Z | Docs scanned: 95 | Elapsed: 0.0s ## Summary @@ -38,6 +38,7 @@ _None. All wikilinks resolve._ - no incoming links: runbooks/expose-service-contabo.md - no incoming links: runbooks/expose-service-edge2.md - no incoming links: runbooks/expose-service-home.md +- no incoming links: runbooks/fleet-magicdns-resolved-migration.md - no incoming links: projects/fleet-platform-baseline.md - no incoming links: docs/software/geo-tools.md - no incoming links: glossary.md @@ -64,7 +65,6 @@ _None. All wikilinks resolve._ - no incoming links: session-resume/SESSION-HANDOFF-meshai-test.md - no incoming links: docs/matrix/synapse_retention_discovery.md - no incoming links: runbooks/syncthing-add-node.md -- no incoming links: plans/vaultwarden-plan.md ## Gaps & suggestions @@ -76,7 +76,6 @@ _None. All wikilinks resolve._ ### True orphans (no inbound link, no shared tag) - `.trash/2026-06-19.md` -- `runbooks/nordvpn-lxc.md` - `runbooks/pipeline-patterns.md` ### Dead wikilinks @@ -94,18 +93,18 @@ Matt decides whether to create a real doc — when he does, future sweeps will l | Term | Docs mentioning it | |------|--------------------| -| `tailscale` | 34 | -| `docker` | 31 | +| `tailscale` | 35 | +| `docker` | 32 | | `proxmox` | 31 | -| `headscale` | 23 | -| `peertube` | 17 | +| `headscale` | 24 | +| `peertube` | 18 | | `mailcow` | 16 | | `meshtastic` | 15 | -| `element` | 13 | -| `forgejo` | 12 | -| `immich` | 12 | -| `nextcloud` | 12 | -| `vaultwarden` | 12 | -| `livesync` | 11 | +| `element` | 14 | +| `forgejo` | 13 | +| `immich` | 13 | +| `nextcloud` | 13 | +| `vaultwarden` | 13 | +| `livesync` | 12 | | `jellyfin` | 11 | | `headplane` | 10 | diff --git a/vault/.obsidian/workspace.json b/vault/.obsidian/workspace.json index 30e1feb..09aa3ff 100644 --- a/vault/.obsidian/workspace.json +++ b/vault/.obsidian/workspace.json @@ -199,17 +199,17 @@ }, "active": "17bd4a6166f789d0", "lastOpenFiles": [ + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.0b86b5de4a11", + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.f94befc79ce2", + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.e8ec4cd814f7", + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.fad0ae6cac23", + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.70c8d22f0a1d", + "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.3a384be4f42c", "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.32d6e661d1df", "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.e72f1c289265", "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.5b1645835a01", "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.d0e7c45a9ac5", "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.96dd988d42a7", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.285d3829268c", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.3ff04dc232a4", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.cebede70f052", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.597a5c023d8a", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.dada4d7c2ef2", - "runbooks/fleet-magicdns-resolved-migration.md.tmp.5281.852dd5a9449f", "runbooks/fleet-magicdns-resolved-migration.md", "projects/fleet-platform-baseline.md", "runbooks/toc-cortex-pve9.2-update.md", diff --git a/vault/runbooks/fleet-magicdns-resolved-migration.md b/vault/runbooks/fleet-magicdns-resolved-migration.md index e440ec9..58e2745 100644 --- a/vault/runbooks/fleet-magicdns-resolved-migration.md +++ b/vault/runbooks/fleet-magicdns-resolved-migration.md @@ -34,13 +34,12 @@ Verified on recon-vm (VM 1130). After migration, each guest must satisfy all of | `systemctl is-active systemd-resolved` | `active` | | `systemctl is-enabled systemd-resolved` | `enabled` | | `/etc/resolv.conf` | symlink → `../run/systemd/resolve/stub-resolv.conf` | -| `resolvectl` Global `DNSMode` | `stub` | +| `resolvectl` Global `resolv.conf mode` | `stub` | | `/etc/systemd/resolved.conf.d/upstream.conf` | `DNS=1.1.1.1 8.8.8.8` | | `journalctl -u tailscaled \| grep "dns: using"` | `dns: using "systemd-resolved" mode` | | `journalctl -u tailscaled \| grep "rc="` | `rc=resolved ... ret=systemd-resolved` | | `resolvectl status tailscale0` DNS | `100.100.100.100` | -| `resolvectl status tailscale0` Domains | `echo6.mesh ~.` | -| `tailscale status --json \| jq .Self.CorpDNS` | `true` | +| `resolvectl status tailscale0` Domains | `echo6.mesh ~.` (accept-dns/CorpDNS on) | | Docker CTs: `/etc/docker/daemon.json` | `"dns": ["1.1.1.1","8.8.8.8"]` | Net result: `*.echo6.mesh` resolves via MagicDNS; public DNS is forwarded through Tailscale when it is up, and falls back to resolved's 1.1.1.1/8.8.8.8 when it is down. @@ -272,11 +271,10 @@ Verify: ```bash pct exec -- bash -lc " resolvectl status tailscale0 -tailscale status --json | grep -i corpDNS " ``` -Expected: `tailscale0` shows `Domains: echo6.mesh ~.` and `CorpDNS: true`. +Expected: `tailscale0` shows `DNS Servers: 100.100.100.100` and `Domains: echo6.mesh ~.`. This confirms accept-dns/CorpDNS is active. (Note: `tailscale status --json | jq .Self.CorpDNS` returns `null` in this Tailscale/Headscale build — use `resolvectl status tailscale0` as the authoritative check. Optionally: `tailscale debug prefs | grep -i corp`.) --- @@ -293,7 +291,7 @@ resolvectl status ``` Confirm: -- Global `DNSMode: stub` +- Global `resolv.conf mode: stub` - `tailscale0` DNS: `100.100.100.100` - `tailscale0` Domains: `echo6.mesh ~.` @@ -425,40 +423,41 @@ Base domain `echo6.mesh` is set in Headscale config. Use these names instead of ## Fleet rollout status +**Migration complete 2026-06-22 — all 19 Tailscale guests + 2 VMs on systemd-resolved split-DNS.** + +Across all 19 guests the recipe held with no failures. The "two tailscaled restarts" pattern (Step 7) was sometimes but not always needed — Bucket I install-path guests often received the `echo6.mesh ~.` domain scope on the first restart. Both boot guards (resolved-ordering.conf + fix-resolv-stub.service) proved necessary and sufficient for reboot persistence across every guest tested. + ### Completed — 2026-06-22 | CT | Host | Bucket | Docker | Notes | |---|---|---|---|---| | CT108 meshai | utility | R | yes | — | -| CT110 peertube | media | I | no | NordVPN allowlist applied | | CT102 searxng | utility | I | yes | — | -| CT111 mcc | media | I | no | Caddy on :80; healthy before+after | | CT112 cobalt | utility | R | yes | No containers deployed; daemon.json DNS pin applied | | CT100 meshmonitor | utility | I | yes | meshai (CT108) stayed healthy throughout; MagicDNS canary validated via media.echo6.mesh | +| CT104 central | utility | I | no | — | +| CT101 caddy | utility | I | no | — | +| CT107 mesh-bridge | utility | I | no | Dual-tailnet bridge (echo6 tailscale0 + IdahoMesh tailscale1); both daemons migrated | +| CT110 peertube | media | I | no | NordVPN allowlist applied | +| CT111 mcc | media | I | no | Caddy on :80; healthy before+after | +| CT103 argus | cloud | R | yes | daemon.json merged (had runtime keys, no dns pin); argus-app stack (grafana/postgres) healthy; pre-existing: argus-app compose lacks restart:always — needs manual `docker compose up -d` after reboot (not a DNS issue) | | CT120 immich | cloud | R | yes | daemon.json pre-pinned; machine_learning unhealthy pre-existing (self-cleared after reboot) | -| CT103 argus | cloud | R | yes | daemon.json merged (had runtime keys, no dns pin); argus-app stack (grafana/postgres) healthy; pre-existing: stack lacks restart-always policy — needs manual `docker compose up -d` after host reboot (not a DNS issue) | | CT121 nextcloud | cloud | R | yes | daemon.json created (missing); 12-container AIO stack (apache/app/db/redis/collabora/…) all healthy before+after; CorpDNS null (expected for this build) — validated via resolvectl tailscale0 echo6.mesh ~.; reboot-persistent | +| CT101 wordpress | edge2 | I | yes | — | +| CT100 pdm | edge2 | I | no | pdm-enterprise apt repo 401s without subscription — disable during install, restore after | +| CT102 vaultwarden | edge2 | I | no | — | +| CT103 forgejo | edge2 | I | no | — | +| CT104 livesync | edge2 | I | no | — | +| CT105 authentik | edge2 | I | yes | — | +| CT106 matrix | edge2 | I | no | — | ### Already compliant (gold-standard VMs) | Guest | Notes | |---|---| | recon-vm (VM 1130) | Reference state; validated | -| arr | Compliant | +| arr (VM 105) | Compliant | ### Pending -| CT | Host | Notes | -|---|---|---| -| CT101 caddy | utility | — | -| CT104 central | utility | — | -| CT107 mesh-bridge | utility | — | -| CT100 pdm | edge2 | Production front-door — do last, one at a time | -| CT101 wordpress | edge2 | Production front-door — do last, one at a time | -| CT102 vaultwarden | edge2 | Production front-door — do last, one at a time | -| CT103 forgejo | edge2 | Production front-door — do last, one at a time | -| CT104 livesync | edge2 | Production front-door — do last, one at a time | -| CT105 authentik | edge2 | Production front-door — do last, one at a time | -| CT106 matrix | edge2 | Production front-door — do last, one at a time | - -> **edge2 CTs are the production front door** (auth, forge, notes, vpn, vault, matrix, element). Migrate them last, strictly one at a time, with a full validation pass between each. +_None — fleet migration complete._