Decommission mesh0 — full OIDC trust model replaces wireguard membership #32

Open
opened 2026-08-06 05:32:34 +00:00 by agent.odin · 4 comments
Collaborator

Stable ID: FM-MESH-DECOMMISSION
Source: owner ruling 2026-08-06
Source status: ratified decision, not yet tracked
Disposition: open — epic, needs decomposition
Blocked by: nothing (but every step inside it blocks on prior steps)

Decision

Wireguard mesh0 is dead. Full OIDC.

Owner ruling 2026-08-06, fleet-wide. The mesh has been dying for months
(keepalive-only, packet loss on mobile, bad on mobile generally). The
direction is now star-and-pull with public et0.pw names — services reach
clients over public DNS, authenticated through Authelia OIDC, not through
wireguard mesh membership.

This is the existing memory direction ("star-and-pull, public et0.pw names")
made canonical: mesh0 stops being the trust boundary.

What this means concretely

Trust boundary shifts

  • Before: wireguard membership is the trust boundary. Services bind to
    wg0, firewall gates on the mesh interface. *.mesh DNS names resolve only
    inside mesh0.
  • After: OIDC is the trust boundary. Services bind to public interfaces,
    gated by Authelia forward_auth (or equivalent). et0.pw names resolve
    publicly.

What dies

  • policies/mesh.nix — wireguard interface, peer config, keepalive
  • contracts/mesh-nodes.nix — the mesh registry
  • integrations/mesh-dns.nix*.mesh DNS resolver
  • outputs/hosts/*/secrets.yamlwireguard/private_key entries
  • Every host's aspects.policies.mesh.privateKeyFile reference
  • Every networking.firewall.interfaces.${mesh_interface} rule

What replaces it

  • OIDC (Authelia on heimdallr) becomes the trust boundary for every
    browser-facing service. Already partially in place — heimdallr runs
    Authelia, and policies/identity exists.
  • Public DNS (et0.pw) replaces *.mesh names. Cloudflare proxy
    certificates already cover the vault names (owner ruling from the audit).
  • Caddy forward_auth replaces mesh-interface firewall scoping for
    services that need authentication. (Exception: git clone over HTTPS —
    see backlog.md, Authelia-as-Forgejo-login-source.)
  • Star-and-pull: each host publishes its services publicly; clients pull
    from et0.pw rather than reaching a mesh address.

Scope of THIS epic

This is a tracking issue. Decomposition happens in sub-tickets. Rough phases:

  1. OIDC readiness. Authelia on heimdallr must be production-grade before
    anything stops trusting mesh0. The deferred Authelia-as-forgejo-login-source
    (backlog.md) unblocks. Caddy forward_auth needs to be a working pattern.

  2. Per-host migration. Each host switches from mesh-interface firewall
    scoping to OIDC-gated public ingress. This is the natural unit of work —
    one host at a time, each verifiable.

  3. Mesh teardown. Once every host has migrated, the wireguard interface,
    peer config, mesh DNS, and mesh secrets are removed fleet-wide.

  4. Documentation. The mesh decommission and the OIDC trust model need a
    wiki page. The deploy law and the migration plan both reference mesh0 as a
    live assumption — those need updating.

Known interactions

  • modron#21 — modron's hardened profile changes from mesh-only firewall to
    OIDC-gated public ingress. First host to adopt the new posture.
  • flaky-mesh#31 — modron decommission; mesh config deleted, not
    transferred.
  • flake-ops#5 — staging VPS payload has no mesh dependencies.
  • backlog.md — "The wolves have no chat presence" assumed mesh0 for
    reaching bifrost's homeserver. That path changes too.
  • DEFERRED.md — Authelia-as-forgejo-login-source becomes a prerequisite,
    not deferred work.
  • flaky-mesh#14 (FM-AUDIT-06) — sudo posture. With no mesh boundary,
    blanket passwordless sudo on servers becomes higher-risk (public ingress).

Open questions

  1. Timeline. Is this a "now" decommission (aggressive, everything moves
    before any more feature work), or a gradual one (each host migrates when
    touched)? The owner's phrasing suggests decided, not exploratory.
  2. SSH access. Today SSH uses mesh0 addresses (just ssh resolves via
    tofu). With mesh0 gone, SSH moves to public addresses + key-only auth.
    Does the justfile's known_hosts model survive?
  3. Monitoring (VictoriaMetrics). Scraping currently reaches exporters over
    mesh0. Public scraping needs authentication or a different transport.
  4. Secrets transport. sops decrypts using the host's SSH host key. With
    mesh0 gone, the key rotation/trust model may need adjustment.

Acceptance

  • Decomposition into per-host sub-tickets, each with a Blocked by chain
  • Authelia production-grade (OIDC issuer, forward_auth working)
  • Every host migrated off mesh0
  • policies/mesh, contracts/mesh-nodes, integrations/mesh-dns deleted
  • No *.mesh DNS name resolves
  • No host has a wireguard private key in sops
  • Deploy law and migration plan updated to reflect OIDC trust model
  • just check green

Provenance

Owner ruling 2026-08-06, stated during modron deploy-rs user story
refinement. Consistent with the existing memory direction ("star-and-pull,
public et0.pw names"), now made the canonical fleet direction.

Wireguard mesh0 status (from memory): keepalive-only, packet loss on mobile,
bad on mobile generally. The mesh has been functionally dead for
communication; this makes it formally dead for trust.

Stable ID: FM-MESH-DECOMMISSION Source: owner ruling 2026-08-06 Source status: ratified decision, not yet tracked Disposition: open — epic, needs decomposition Blocked by: nothing (but every step inside it blocks on prior steps) ## Decision **Wireguard mesh0 is dead. Full OIDC.** Owner ruling 2026-08-06, fleet-wide. The mesh has been dying for months (keepalive-only, packet loss on mobile, bad on mobile generally). The direction is now star-and-pull with public `et0.pw` names — services reach clients over public DNS, authenticated through Authelia OIDC, not through wireguard mesh membership. This is the existing memory direction ("star-and-pull, public et0.pw names") made canonical: mesh0 stops being the trust boundary. ## What this means concretely ### Trust boundary shifts - **Before:** wireguard membership is the trust boundary. Services bind to `wg0`, firewall gates on the mesh interface. `*.mesh` DNS names resolve only inside mesh0. - **After:** OIDC is the trust boundary. Services bind to public interfaces, gated by Authelia `forward_auth` (or equivalent). `et0.pw` names resolve publicly. ### What dies - `policies/mesh.nix` — wireguard interface, peer config, keepalive - `contracts/mesh-nodes.nix` — the mesh registry - `integrations/mesh-dns.nix` — `*.mesh` DNS resolver - `outputs/hosts/*/secrets.yaml` — `wireguard/private_key` entries - Every host's `aspects.policies.mesh.privateKeyFile` reference - Every `networking.firewall.interfaces.${mesh_interface}` rule ### What replaces it - **OIDC (Authelia on heimdallr)** becomes the trust boundary for every browser-facing service. Already partially in place — heimdallr runs Authelia, and `policies/identity` exists. - **Public DNS (`et0.pw`)** replaces `*.mesh` names. Cloudflare proxy certificates already cover the vault names (owner ruling from the audit). - **Caddy `forward_auth`** replaces mesh-interface firewall scoping for services that need authentication. (Exception: `git clone` over HTTPS — see backlog.md, Authelia-as-Forgejo-login-source.) - **Star-and-pull:** each host publishes its services publicly; clients pull from `et0.pw` rather than reaching a mesh address. ## Scope of THIS epic This is a tracking issue. Decomposition happens in sub-tickets. Rough phases: 1. **OIDC readiness.** Authelia on heimdallr must be production-grade before anything stops trusting mesh0. The deferred Authelia-as-forgejo-login-source (backlog.md) unblocks. Caddy `forward_auth` needs to be a working pattern. 2. **Per-host migration.** Each host switches from mesh-interface firewall scoping to OIDC-gated public ingress. This is the natural unit of work — one host at a time, each verifiable. 3. **Mesh teardown.** Once every host has migrated, the wireguard interface, peer config, mesh DNS, and mesh secrets are removed fleet-wide. 4. **Documentation.** The mesh decommission and the OIDC trust model need a wiki page. The deploy law and the migration plan both reference mesh0 as a live assumption — those need updating. ## Known interactions - **modron#21** — modron's hardened profile changes from mesh-only firewall to OIDC-gated public ingress. First host to adopt the new posture. - **flaky-mesh#31** — modron decommission; mesh config deleted, not transferred. - **flake-ops#5** — staging VPS payload has no mesh dependencies. - **backlog.md** — "The wolves have no chat presence" assumed mesh0 for reaching bifrost's homeserver. That path changes too. - **DEFERRED.md** — Authelia-as-forgejo-login-source becomes a prerequisite, not deferred work. - **flaky-mesh#14** (FM-AUDIT-06) — sudo posture. With no mesh boundary, blanket passwordless sudo on servers becomes higher-risk (public ingress). ## Open questions 1. **Timeline.** Is this a "now" decommission (aggressive, everything moves before any more feature work), or a gradual one (each host migrates when touched)? The owner's phrasing suggests decided, not exploratory. 2. **SSH access.** Today SSH uses mesh0 addresses (`just ssh` resolves via tofu). With mesh0 gone, SSH moves to public addresses + key-only auth. Does the justfile's `known_hosts` model survive? 3. **Monitoring (VictoriaMetrics).** Scraping currently reaches exporters over mesh0. Public scraping needs authentication or a different transport. 4. **Secrets transport.** sops decrypts using the host's SSH host key. With mesh0 gone, the key rotation/trust model may need adjustment. ## Acceptance - [ ] Decomposition into per-host sub-tickets, each with a Blocked by chain - [ ] Authelia production-grade (OIDC issuer, forward_auth working) - [ ] Every host migrated off mesh0 - [ ] `policies/mesh`, `contracts/mesh-nodes`, `integrations/mesh-dns` deleted - [ ] No `*.mesh` DNS name resolves - [ ] No host has a wireguard private key in sops - [ ] Deploy law and migration plan updated to reflect OIDC trust model - [ ] `just check` green ## Provenance Owner ruling 2026-08-06, stated during modron deploy-rs user story refinement. Consistent with the existing memory direction ("star-and-pull, public et0.pw names"), now made the canonical fleet direction. Wireguard mesh0 status (from memory): keepalive-only, packet loss on mobile, bad on mobile generally. The mesh has been functionally dead for communication; this makes it formally dead for trust.
Author
Collaborator

Owner ruling 2026-08-06: timeline and difficulty

Gradual, but there isn't much. The fleet is small and most services are
trivially behind forward_auth. Two are hard:

The two hard migrations

Matrix (tuwunel on bifrost)

  • Federation: /.well-known/matrix/* delegation must survive the move from
    mesh-only to public. A delegation that serves 200 with subtly wrong JSON
    fails federation silently — the same trap DEFERRED.md already flags.
  • Client connections: mobile clients currently reach the homeserver over
    mesh0 (0.0.0.0:6167, plain HTTP, mesh-is-the-encryption). Moving to public
    means TLS + a public hostname (matrix.et0.pw already exists).
  • The wolves' planned accounts (@freki:et0.pw, @geri:et0.pw) assumed
    mesh-only plain HTTP to bifrost:6167. That path disappears.

Forgejo HTTPS clone

  • git clone over HTTPS is performed by git, not a browser — it cannot
    follow a redirect to a login page. Forward_auth breaks git over HTTPS
    (backlog.md, DEFERRED.md both flag this).
  • The solution is already scoped: OIDC as a Forgejo login source (not
    forward_auth). Authelia OIDC → Forgejo oauth2 auth source. Web UI goes
    through Authelia; git over HTTPS keeps using Forgejo tokens.
  • This was deferred ("not until forge is stable"). It is now a prerequisite
    of the mesh decommission, not deferrable work.

The easy rest

Everything else browser-facing is forward_auth against Authelia:
dashboards, whoami, victoria, librefang, the Caddy-served sites. One pattern,
applied per host. The hard part is already built — Caddy supports
forward_auth natively, and heimdallr already runs Authelia.

Updated phasing

  1. OIDC readiness (unchanged): Authelia production-grade, forward_auth
    pattern proven.
  2. Forgejo OIDC login source (was deferred, now prerequisite): unblock
    the hard one first.
  3. Matrix public migration (the other hard one): TLS + public hostname,
    well-known delegation verified.
  4. Everything else: per-host forward_auth, gradual.
  5. Mesh teardown: once nothing depends on mesh0.

What this settles from the open questions

  • Q1 (timeline): gradual. But "gradual" means "per-host when touched," not
    "indefinitely deferred." The two hard ones get explicit tickets.
  • Authelia prerequisite is confirmed: Forgejo OIDC login source moves from
    DEFERRED.md to blocked-on-nothing.

Sub-tickets to file

  • Forgejo: Authelia OIDC as login source (was DEFERRED.md)
  • Matrix: public migration (TLS + well-known verification)
  • Per-host forward_auth migration (one per browser-facing host)
## Owner ruling 2026-08-06: timeline and difficulty **Gradual, but there isn't much.** The fleet is small and most services are trivially behind `forward_auth`. Two are hard: ### The two hard migrations **Matrix (tuwunel on bifrost)** - Federation: `/.well-known/matrix/*` delegation must survive the move from mesh-only to public. A delegation that serves 200 with subtly wrong JSON fails federation silently — the same trap DEFERRED.md already flags. - Client connections: mobile clients currently reach the homeserver over mesh0 (`0.0.0.0:6167`, plain HTTP, mesh-is-the-encryption). Moving to public means TLS + a public hostname (`matrix.et0.pw` already exists). - The wolves' planned accounts (`@freki:et0.pw`, `@geri:et0.pw`) assumed mesh-only plain HTTP to bifrost:6167. That path disappears. **Forgejo HTTPS clone** - `git clone` over HTTPS is performed by git, not a browser — it cannot follow a redirect to a login page. Forward_auth **breaks git over HTTPS** (backlog.md, DEFERRED.md both flag this). - The solution is already scoped: OIDC as a Forgejo **login source** (not forward_auth). Authelia OIDC → Forgejo `oauth2` auth source. Web UI goes through Authelia; git over HTTPS keeps using Forgejo tokens. - This was deferred ("not until forge is stable"). It is now a prerequisite of the mesh decommission, not deferrable work. ### The easy rest Everything else browser-facing is `forward_auth` against Authelia: dashboards, whoami, victoria, librefang, the Caddy-served sites. One pattern, applied per host. The hard part is already built — Caddy supports `forward_auth` natively, and heimdallr already runs Authelia. ### Updated phasing 1. **OIDC readiness** (unchanged): Authelia production-grade, forward_auth pattern proven. 2. **Forgejo OIDC login source** (was deferred, now prerequisite): unblock the hard one first. 3. **Matrix public migration** (the other hard one): TLS + public hostname, well-known delegation verified. 4. **Everything else**: per-host `forward_auth`, gradual. 5. **Mesh teardown**: once nothing depends on mesh0. ### What this settles from the open questions - **Q1 (timeline): gradual.** But "gradual" means "per-host when touched," not "indefinitely deferred." The two hard ones get explicit tickets. - **Authelia prerequisite is confirmed**: Forgejo OIDC login source moves from DEFERRED.md to blocked-on-nothing. ### Sub-tickets to file - Forgejo: Authelia OIDC as login source (was DEFERRED.md) - Matrix: public migration (TLS + well-known verification) - Per-host forward_auth migration (one per browser-facing host)
Author
Collaborator

Owner question 2026-08-06: SSH discovery without mesh0

The easy-seeming questions (DNS, forward_auth, TLS) are settled or scoped.
This one is genuinely open: how does just ssh find a distant node's
address when mesh0 is gone?

The diagnostic that settles it

Are vpsFree public addresses stable?

Today just ssh reads the address from OpenTofu state (tofu output -raw address). That works because tofu tracks what vpsAdmin granted. The question
is whether that address survives reboots, migrations, or vpsFree-side changes.

  • If stable (static public IPv4/IPv6): DNS suffices. bifrost.et0.pw
    points at the public address; ssh [email protected]. The tofu state and
    known_hosts model survive unchanged — just the address type changes from
    mesh to public. One-time DNS record per host.

  • If unstable (SLAAC with privacy extensions, or address rotation): DNS
    goes stale on every change. A discovery system is needed — dynamic DNS, a
    coordination service, or the host publishing its current address somewhere
    queryable.

This is a five-minute check against a running host — does the tofu-recorded
address match ip addr after a reboot? Owner or Fizz can answer it; I can't
reach the hosts from here.

Options, if discovery is needed

Recorded so the choice has a named surface, not to decide now:

  1. Dynamic DNS. Each host updates its own et0.pw record on boot (or on
    address change). ddclient, a NixOS systemd service, or a Caddy-level
    hook. Simple, no new infrastructure, depends on a DNS API.

  2. OpenTofu as discovery. tofu already tracks the address. If it stays
    authoritative, just ssh keeps working as-is — tofu output is the
    discovery query. This is the current mechanism; the question is whether
    it's stable enough to rely on without a mesh fallback.

  3. A coordination/mesh-discovery service. Something like a lightweight
    registry where hosts publish their current address and clients query it.
    Tailscale's coordination server does this; a bare version is a single HTTP
    endpoint returning {host: address}. Overkill if a simpler option works.

  4. Magic DNS / overlay. A Tailscale/Headscale/Zerotier-style overlay that
    gives each host a stable name regardless of its underlying address. This
    is essentially rebuilding mesh0 with a better protocol. May be the right
    answer if mobile client connectivity also needs it (the original mesh0
    failure was on mobile).

Why this isn't just an SSH question

SSH is the first consumer, but not the only one. Monitoring scraping
(VictoriaMetrics reaching exporters), secrets transport (sops using the host's
SSH key), and any agent reaching a distant service all depend on knowing where
a host is. If discovery is needed for SSH, it's needed for those too.

Not decided here

This stays an open question on #32 until the stability diagnostic is run. The
mechanism choice follows the answer — don't pick a discovery system before
knowing whether one is needed.

Filed as open question #2 (SSH), refined

The original Q2 on #32 asked "does the known_hosts model survive?" This
refines it: known_hosts survives any mechanism that produces a stable address.
The question is upstream of known_hosts — it's about address stability.

## Owner question 2026-08-06: SSH discovery without mesh0 The easy-seeming questions (DNS, forward_auth, TLS) are settled or scoped. This one is genuinely open: **how does `just ssh` find a distant node's address when mesh0 is gone?** ### The diagnostic that settles it **Are vpsFree public addresses stable?** Today `just ssh` reads the address from OpenTofu state (`tofu output -raw address`). That works because tofu tracks what vpsAdmin granted. The question is whether that address survives reboots, migrations, or vpsFree-side changes. - **If stable (static public IPv4/IPv6):** DNS suffices. `bifrost.et0.pw` points at the public address; `ssh [email protected]`. The tofu state and `known_hosts` model survive unchanged — just the address type changes from mesh to public. One-time DNS record per host. - **If unstable (SLAAC with privacy extensions, or address rotation):** DNS goes stale on every change. A discovery system is needed — dynamic DNS, a coordination service, or the host publishing its current address somewhere queryable. This is a five-minute check against a running host — does the tofu-recorded address match `ip addr` after a reboot? Owner or Fizz can answer it; I can't reach the hosts from here. ### Options, if discovery is needed Recorded so the choice has a named surface, not to decide now: 1. **Dynamic DNS.** Each host updates its own `et0.pw` record on boot (or on address change). ddclient, a NixOS systemd service, or a Caddy-level hook. Simple, no new infrastructure, depends on a DNS API. 2. **OpenTofu as discovery.** tofu already tracks the address. If it stays authoritative, `just ssh` keeps working as-is — tofu output is the discovery query. This is the current mechanism; the question is whether it's stable enough to rely on without a mesh fallback. 3. **A coordination/mesh-discovery service.** Something like a lightweight registry where hosts publish their current address and clients query it. Tailscale's coordination server does this; a bare version is a single HTTP endpoint returning `{host: address}`. Overkill if a simpler option works. 4. **Magic DNS / overlay.** A Tailscale/Headscale/Zerotier-style overlay that gives each host a stable name regardless of its underlying address. This is essentially rebuilding mesh0 with a better protocol. May be the right answer if mobile client connectivity also needs it (the original mesh0 failure was on mobile). ### Why this isn't just an SSH question SSH is the first consumer, but not the only one. Monitoring scraping (VictoriaMetrics reaching exporters), secrets transport (sops using the host's SSH key), and any agent reaching a distant service all depend on knowing where a host is. If discovery is needed for SSH, it's needed for those too. ### Not decided here This stays an open question on #32 until the stability diagnostic is run. The mechanism choice follows the answer — don't pick a discovery system before knowing whether one is needed. ### Filed as open question #2 (SSH), refined The original Q2 on #32 asked *"does the known_hosts model survive?"* This refines it: known_hosts survives any mechanism that produces a stable address. The question is upstream of known_hosts — it's about address stability.
Author
Collaborator

Owner refinement 2026-08-06: CF proxy kills DNS-for-SSH

The DNS answer is wrong, and not because addresses might be unstable.

CF proxy hides origin IPs by design. dig bifrost.et0.pw returns
Cloudflare edge IPs, not the host's real address. CF only proxies HTTP(S),
not raw TCP — so you cannot SSH to a CF-resolved address. Ever.

And when CF itself is unreachable (owner: "sometimes we need alternative
access"
), DNS resolution fails entirely. CF becomes a single point of failure
for any path that depends on it.

What this eliminates

  • Plain DNS (option 1) is dead for SSH. Grey-clouding a record (CF DNS-only
    mode, exposing the real IP) works mechanically, but defeats the proxy
    protection for that hostname and leaks the origin IP.
  • DNS-based discovery works for HTTP(S) services (Caddy, forward_auth,
    browser traffic) because CF proxies those. It does not work for SSH,
    monitoring scraping, sops key trust, or any non-HTTP TCP.

What this means for the remaining options

The discovery question is now sharper: non-HTTP TCP needs a path that
bypasses CF entirely.
That's SSH, VictoriaMetrics scraping, and any
agent-to-service reachability that isn't HTTP.

The surviving options, refined:

  1. OpenTofu state as the primary discovery. Tofu already tracks the real
    address, bypasses CF, and is the current mechanism. If vpsFree addresses
    are stable (still the open diagnostic), tofu is both the primary and the
    CF-independent fallback. just ssh already uses this path and it works.

  2. Host-published address, not through CF. Each host publishes its real
    address somewhere queryable that doesn't depend on CF — a lightweight
    registry endpoint, a DNS TXT record on a non-proxied zone, or an append
    to a known location (Forgejo, a status file). This is the "alternative
    access" the owner is asking about: when CF is down, how do you find the
    host?

  3. Overlay network (Tailscale/Headscale/Wireguard-as-discovery). Gives
    each host a stable address that doesn't depend on DNS or CF at all. This
    is rebuilding mesh0 with better properties — the original mesh0 failure
    was mobile clients and packet loss, not the concept of an overlay. An
    overlay that handles mobile well (Tailscale's DERP relays, for instance)
    could serve both SSH discovery and mobile client connectivity.

The real question

It's not "do we need discovery" — CF proxy means we do, for everything
that isn't HTTP(S). The question is: is tofu state reliable enough to be
the sole discovery path, or do we need a second independent channel?

The owner's "sometimes we need alternative access" suggests tofu alone is
not enough — there are scenarios where neither CF DNS nor the current
tofu-tracked address gets you in. Those scenarios need naming before picking
a mechanism.

## Owner refinement 2026-08-06: CF proxy kills DNS-for-SSH The DNS answer is wrong, and not because addresses might be unstable. **CF proxy hides origin IPs by design.** `dig bifrost.et0.pw` returns Cloudflare edge IPs, not the host's real address. CF only proxies HTTP(S), not raw TCP — so you cannot SSH to a CF-resolved address. Ever. And when CF itself is unreachable (owner: *"sometimes we need alternative access"*), DNS resolution fails entirely. CF becomes a single point of failure for any path that depends on it. ### What this eliminates - **Plain DNS (option 1) is dead for SSH.** Grey-clouding a record (CF DNS-only mode, exposing the real IP) works mechanically, but defeats the proxy protection for that hostname and leaks the origin IP. - **DNS-based discovery works for HTTP(S) services** (Caddy, forward_auth, browser traffic) because CF proxies those. It does not work for SSH, monitoring scraping, sops key trust, or any non-HTTP TCP. ### What this means for the remaining options The discovery question is now sharper: **non-HTTP TCP needs a path that bypasses CF entirely.** That's SSH, VictoriaMetrics scraping, and any agent-to-service reachability that isn't HTTP. The surviving options, refined: 1. **OpenTofu state as the primary discovery.** Tofu already tracks the real address, bypasses CF, and is the current mechanism. If vpsFree addresses are stable (still the open diagnostic), tofu is both the primary and the CF-independent fallback. `just ssh` already uses this path and it works. 2. **Host-published address, not through CF.** Each host publishes its real address somewhere queryable that doesn't depend on CF — a lightweight registry endpoint, a DNS TXT record on a non-proxied zone, or an append to a known location (Forgejo, a status file). This is the "alternative access" the owner is asking about: when CF is down, how do you find the host? 3. **Overlay network (Tailscale/Headscale/Wireguard-as-discovery).** Gives each host a stable address that doesn't depend on DNS or CF at all. This is rebuilding mesh0 with better properties — the original mesh0 failure was mobile clients and packet loss, not the concept of an overlay. An overlay that handles mobile well (Tailscale's DERP relays, for instance) could serve both SSH discovery and mobile client connectivity. ### The real question It's not "do we need discovery" — CF proxy means we **do**, for everything that isn't HTTP(S). The question is: **is tofu state reliable enough to be the sole discovery path, or do we need a second independent channel?** The owner's *"sometimes we need alternative access"* suggests tofu alone is not enough — there are scenarios where neither CF DNS nor the current tofu-tracked address gets you in. Those scenarios need naming before picking a mechanism.
Author
Collaborator

Owner decision 2026-08-06: Headscale

Freenet evaluated (interesting talk — hole-punching, no coordination server),
but it's a content-routing platform, not a TCP tunnel. Wrong shape for this.

Headscale. Self-hosted Tailscale control server. Replaces mesh0's role
(stable addresses for non-HTTP TCP, mobile-friendly) with better properties
(DERP relay fallback, battle-tested NAT traversal, NixOS first-class module).

Resolves open question #2 on this issue: discovery without CF for SSH,
monitoring scraping, sops transport, and mobile clients. Headscale gives every
host a stable 100.x.y.z address that bypasses CF entirely.

Filed as #35.

## Owner decision 2026-08-06: Headscale Freenet evaluated (interesting talk — hole-punching, no coordination server), but it's a content-routing platform, not a TCP tunnel. Wrong shape for this. **Headscale.** Self-hosted Tailscale control server. Replaces mesh0's role (stable addresses for non-HTTP TCP, mobile-friendly) with better properties (DERP relay fallback, battle-tested NAT traversal, NixOS first-class module). Resolves open question #2 on this issue: discovery without CF for SSH, monitoring scraping, sops transport, and mobile clients. Headscale gives every host a stable `100.x.y.z` address that bypasses CF entirely. Filed as #35.
Commenting is not possible because the repository is archived.
No description provided.