JarvisOS HomeLab status
No signal

Public ingress

5 paths · 8 names · 8/10 measurements are real

Two ways into this estate that stand on no common host. The mechanism is one Cloudflare named tunnel with a connector on VIN and a connector on Home1: both register with the same tunnel, both answer for the same public names, and the edge stops using a connector that stops answering — so failover between them is the vendor's job and needs no DNS record to move, which matters because the records are the owner's and JarvisOS holds no credential for them. Two edges already exist and neither is redundant: Caddy on VIN holds the JarvisOS names, and Cloudflare reaches Coolify's Traefik on Home1 for the twenty-two applications the owner runs there. Every domain has exactly one way in. The reachability numbers here were measured from this node; the thirty-second failover was not, and the register says which is which on every row.

Nothing on this page is a declared survival. A path is a list of hops and each hop names the host it runs on; which hosts a path stands on, whether two paths are independent, and what one host or one vendor still takes down on its own are all recomputed from those legs on every render. A verdict is the weakest of three separate survivals — a path, a backend that path can still reach, and an authenticator that will still say yes — and it names which one gave way, because the repair is different for each. The console measures nothing: asking whether a public name answers means making a request from outside the estate, and that is scripts/jarvisos-ingress.mjs, which cannot create a tunnel, move a record or stop a connector.

No single host — today 0/5 critical names that survive losing any one host
No single host — designed 3/5 the same number once the register is built
Survive VPS and rack loss 3/5 0 of them today
Paths running 2/5 3 planned
Measured 8/10 last [object Object]
Findings 25 0 fatal · 0 accepted

What survives — designed

every path, built
Published name The VPS is goneHome1 is goneThe whole home rack is goneThe home uplink is downThe tailnet is partitionedThe Cloudflare proxy and tunnel are downCloudflare authoritative DNS is down
auth.collinscreations.co.uk critical automatic 30s automatic automatic automatic automatic manual 10 min no path
jarvis.collinscreations.co.uk critical automatic 30s automatic automatic automatic automatic manual 10 min no path
ai.collinscreations.co.uk critical automatic no backend no backend no backend automatic no path no path
status.collinscreations.co.uk critical automatic 30s automatic automatic automatic automatic manual 10 min no path
ha.collinscreations.co.uk critical automatic no backend no backend no backend automatic no path no path
tm.collinscreations.co.uk important automatic lost lost lost automatic no path no path
myfinance.collinscreations.co.uk important automatic lost lost lost automatic no path no path
batteries.collinscreations.co.uk ordinary automatic lost lost lost automatic no path no path

What survives — today

only what is running

The difference between this table and the one above it is the work. Two edges already exist in this estate and neither is redundant: one holds the JarvisOS names, the other holds the applications, and every name has exactly one way in.

Published name The VPS is goneHome1 is goneThe whole home rack is goneThe home uplink is downThe tailnet is partitionedThe Cloudflare proxy and tunnel are downCloudflare authoritative DNS is down
auth.collinscreations.co.uk critical lost no state no state no state automatic no path no path
jarvis.collinscreations.co.uk critical lost automatic automatic automatic automatic no path no path
ai.collinscreations.co.uk critical lost lost lost lost lost lost lost
status.collinscreations.co.uk critical lost automatic automatic automatic automatic no path no path
ha.collinscreations.co.uk critical automatic lost lost lost automatic no path no path
tm.collinscreations.co.uk important automatic lost lost lost automatic no path no path
myfinance.collinscreations.co.uk important automatic lost lost lost automatic no path no path
batteries.collinscreations.co.uk ordinary automatic lost lost lost automatic no path no path

What one thing still takes down

derived, one loss at a time
Published name Hosts — today Hosts — designed Vendors — designed
auth.collinscreations.co.uk vin, home1 none cloudflare-dns
jarvis.collinscreations.co.uk vin none cloudflare-dns
ai.collinscreations.co.uk unserved home1 cloudflare-dns, cloudflare-edge
status.collinscreations.co.uk vin none cloudflare-dns
ha.collinscreations.co.uk home1 home1 cloudflare-dns, cloudflare-edge
tm.collinscreations.co.uk home1 home1 cloudflare-dns, cloudflare-edge, isp-uplink
myfinance.collinscreations.co.uk home1 home1 cloudflare-dns, cloudflare-edge, isp-uplink
batteries.collinscreations.co.uk home1 home1 cloudflare-dns, cloudflare-edge, isp-uplink

Every path in this register carries a tailnet leg, and Tailscale is not on this list for the console — because the console has a copy beside each connector and never needs the transport. That is the difference between counting the legs and asking the question.

The ways in

2 running, 3 planned

Caddy on VIN (the edge as it stands)

origin-proxy · running

Stands on: vin · Through: cloudflare-dns, cloudflare-edge, tailscale

Described here so that the design has something to be measured against. Its legs are the reason the estate currently loses every published JarvisOS name with one host: three of the five run on VIN.

Hop Runs on Does When it goes
public-dns cloudflare-dns Resolves the published name to a Cloudflare anycast address. The name does not resolve and nothing downstream is reached.
vendor-edge cloudflare-edge Terminates TLS for the browser, absorbs the public internet and hides VIN's address. Proxied names fail at the edge before a request ever reaches the origin.
origin-ingress vin Terminates the origin TLS leg on VIN and is the only listener on :80 and :443 that JarvisOS owns. Every published JarvisOS name stops answering. This is the single point of failure the register exists to remove.
auth vin Authenticates every request before it reaches an upstream, as a Caddy forward_auth subrequest. Requests fail closed with 403. Correct behaviour, and not the same thing as the site being up.
private-transport tailscale Carries the request from VIN to a backend on another host, with no inbound port open on that host. VIN can only serve backends that run on VIN.

Failover

automatic, none needed — moved by Nothing has to move: this is where the proxied record already points.

Caddy active health checks against each upstream over the tailnet; nothing checks Caddy itself from outside the estate.

Never measured — this number is a prediction.

Certificate

Let's Encrypt, via Caddy's built-in ACME client, presented to The Cloudflare edge on the origin leg, and directly to the browser whenever a record is grey-clouded.

Key material: vin · Renewal: Automatic, by Caddy, roughly 30 days before expiry over the HTTP-01 challenge on :80.

If this path is lost: Renewal stops with VIN and nobody is told, because an expiring certificate is silent until the day it expires. The account key and certificates are in the t0 backup tier, so a rebuilt VIN restores rather than re-issues — but if VIN is gone for more than ~30 days the certificates expire wherever they were restored to.

Withdraw this path: This path predates the register. Withdrawing it means pointing the affected names at the tunnel and stopping Caddy — which is step 5 of the tunnel path's cutover, not an operation of its own.

Cloudflare to Coolify's Traefik on Home1 (the other edge that already exists)

origin-proxy · running

Stands on: home1 · Through: cloudflare-dns, cloudflare-edge, isp-uplink

Added because a probe from this node found it, not because a document described it. status.collinscreations.co.uk answered 503 while ha, tm and batteries answered 200 or 302 — the applications are not being served through Caddy on VIN. How Cloudflare reaches Traefik here is the open question: an existing tunnel connector and a forwarded port on the router are indistinguishable from outside, and the estate has a standing rule against the second. See the gap ingress-home1-edge-mechanism-unverified.

Hop Runs on Does When it goes
public-dns cloudflare-dns Resolves the application's name — in practice the wildcard *.collinscreations.co.uk that Coolify holds on home1. The name does not resolve.
vendor-edge cloudflare-edge Terminates TLS for the browser and forwards to the home origin. Proxied names fail at the edge.
origin-ingress home1 Coolify's Traefik answers for the wildcard domain and routes to the container on its own node. This is where the twenty-two applications the owner already runs are actually served from. Every one of those applications stops answering, whatever VIN is doing.
node-routing home1 Routes to the specific container and terminates the node-local TLS Coolify issues. Containers are unreachable even while running.

Failover

automatic, none needed — moved by Nothing has to move: this is where the wildcard already points.

Cloudflare's origin health only. Nothing in this estate checks it, and the applications behind it largely declare no health check at all — the estate register records running:unknown for most of them, which is a status Coolify can never turn into unhealthy.

Never measured — this number is a prediction.

Certificate

Cloudflare Universal SSL to the browser; Coolify-issued Let's Encrypt certificates on the origin leg., presented to The Cloudflare edge on the origin leg.

Key material: home1 · Renewal: Automatic, by Coolify's Traefik, per application domain.

If this path is lost: Renewal stops with home1 for every one of these names at once. Coolify's ACME state is part of the container definitions in the t0 backup tier, so a rebuild restores rather than re-issues.

Withdraw this path: Pre-existing. Nothing in this register proposes withdrawing it; the tunnel connector on home1 is designed to sit alongside it and take names over one at a time.

Cloudflare Tunnel connector on VIN

named-tunnel · planned

Stands on: vin · Through: cloudflare-dns, cloudflare-edge, tailscale

This connector alone is not redundancy — it stands on the same host as the path it replaces. It is here because it is half of a pair and because it is the half that can be built and proven without touching the home rack.

Hop Runs on Does When it goes
public-dns cloudflare-dns Resolves the published name to the tunnel's CNAME target — a tunnel id, not a host address. This is the property the whole design rests on: the record names the tunnel, so which connector answers is not a DNS question. The name does not resolve.
vendor-edge cloudflare-edge Terminates TLS for the browser and hands the request to whichever connector of this tunnel is registered and answering. Both connectors are bypassed; the tunnel has no meaning without the edge that terminates it.
origin-ingress vin Holds four outbound QUIC connections to the Cloudflare edge and forwards to configured origins. Opens no inbound port. This connector deregisters and the edge sends every request to the Home1 connector instead.
auth vin Authenticates the request before it leaves the connector for an origin. Requests through this connector fail closed.
private-transport tailscale Carries the request onward to a backend on Home1 or the NAS. This connector can only serve backends that run on VIN.

Failover

automatic, 30s — moved by The Cloudflare edge, between the connectors of one named tunnel.

The Cloudflare edge tracks each connector's registered connections. A connector that stops answering is removed from the tunnel's pool and requests go to the remaining connectors.

Never measured — this number is a prediction.

Certificate

Cloudflare Universal SSL, presented to The browser. The connector leg is authenticated by the tunnel's own credential, not by a certificate this estate issues or renews.

Key material: not on any host of ours · Renewal: Automatic at Cloudflare. No ACME client, no challenge, no :80 listener, and no renewal that can stop because a host is down.

If this path is lost: Nothing. This is the largest single reliability difference between this path and the Caddy one: losing the host does not put a clock on a certificate.

Cutover — every step with the way back out beside it

  1. Create the named tunnel [owner, downtime: none]
    Owner creates a named tunnel `jarvis-edge` in the Cloudflare Zero Trust dashboard and downloads one credential file per connector host.
    Verify: `cloudflared tunnel list` shows `jarvis-edge` with zero connections.
    Undo: Delete the tunnel. Nothing points at it yet, so this affects no published name.
  2. Install the connector on VIN [jarvisos, downtime: none]
    Install cloudflared on VIN, place the credential at /etc/cloudflared/, and run it as an unprivileged systemd unit with no ingress rules yet.
    Verify: `cloudflared tunnel info jarvis-edge` shows one connection from VIN; no published name has changed.
    Undo: `systemctl disable --now cloudflared`. The connector deregisters; no record has moved, so no traffic is affected.
  3. Move one name, not the estate [owner, downtime: up to one TTL on one name]
    Add an ingress rule for status.collinscreations.co.uk only, and repoint that one CNAME at the tunnel.
    Verify: The name answers through the tunnel and the response carries the expected auth challenge; every other name is untouched and still served by Caddy.
    Undo: Repoint the single CNAME back at the Caddy origin. One record, one name, one TTL — which is the entire reason for moving one name first.

Withdraw this path: Stop the connector and repoint any CNAME that names the tunnel back at the Caddy origin. Cloudflare-issued certificates need no cleanup, and Caddy's certificates were never withdrawn, so the old path is still warm.

Cloudflare Tunnel connector on Home1

named-tunnel · planned

Stands on: home1 · Through: cloudflare-dns, cloudflare-edge, isp-uplink, tailscale

This is the path that answers HOST-026. It shares no host with the Caddy edge and no host with the VIN connector, so losing the VPS leaves it serving and losing the home rack leaves the VIN connector serving. What it cannot do is conjure a backend: a name whose application only exists on Home1 is still lost when Home1 is, and the matrix says so per domain rather than averaging it away.

Hop Runs on Does When it goes
public-dns cloudflare-dns Resolves the published name to the same tunnel CNAME the VIN connector answers for. One name, one record, two connectors. The name does not resolve.
vendor-edge cloudflare-edge Terminates TLS for the browser and selects a registered connector. Both connectors are bypassed.
origin-ingress home1 Holds outbound connections to the Cloudflare edge from inside the home rack. Opens no inbound port on the router, which is what makes this compatible with the standing rule that Home1 never has one. This connector deregisters and the edge sends every request to the VIN connector instead.
auth home1 Authenticates the request on Home1, using the same session-signing key as the VIN authenticator so that a session survives moving between connectors. Requests through this connector fail closed. This instance is the reason the identity register's home1 standby stops being optional.
node-routing home1 Routes to the container on Home1 that actually holds the application. For the twenty-two applications already on this node this hop is local and needs no transport at all. Containers on Home1 are unreachable even while running.
private-transport tailscale Carries the request onward when the backend is on VIN or the NAS rather than on Home1. This connector can only serve backends that run on Home1 — which, today, is almost all of them.

Failover

automatic, 30s — moved by The Cloudflare edge, between the connectors of one named tunnel.

The Cloudflare edge tracks each connector's registered connections and removes one that stops answering.

Never measured — this number is a prediction.

Certificate

Cloudflare Universal SSL, presented to The browser — the same certificate the VIN connector's requests are served under, because it belongs to the name and the edge, not to the connector.

Key material: not on any host of ours · Renewal: Automatic at Cloudflare.

If this path is lost: Nothing. A failover between connectors involves no certificate at all: the browser's TLS session is with Cloudflare and never notices which connector answered behind it.

Cutover — every step with the way back out beside it

  1. Install the second connector [jarvisos, downtime: none]
    Install cloudflared on Home1 with its own credential file for the same tunnel, as an unprivileged systemd unit with the same ingress rules as the VIN connector.
    Verify: `cloudflared tunnel info jarvis-edge` shows two connections from two hosts.
    Undo: `systemctl disable --now cloudflared` on Home1. The tunnel falls back to one connector, which is where it started.
  2. Stand up the Home1 authenticator [jarvisos, downtime: none]
    Run the second forward-auth instance on Home1 with the same session-signing key, per the identity register's auth-home1 instance.
    Verify: A session issued through the VIN connector is accepted by the Home1 connector without a re-login.
    Undo: Stop the instance and remove the Home1 connector's ingress rules in the same change. Leaving a connector up with no authenticator behind it would publish names with no lock, which is the one outcome this register treats as fatal.
  3. Measure the failover before believing it [jarvisos, downtime: whatever the measurement discovers, which is the number being measured]
    Stop one connector, and time how long the published name takes to answer again from outside the estate. Repeat for the other connector. Record both with `jarvisos-ingress.mjs record`.
    Verify: Two measurements of kind `failover`, mode `measured`, each carrying the observed seconds and the raw output they came from.
    Undo: Start the connector again. The measurement is the whole point of the step and stopping a connector is the drill, not the damage.

Withdraw this path: Stop the Home1 connector. The tunnel keeps working on the VIN connector alone, no record moves, and no certificate is affected. This is the cheapest rollback of any path here and it is the reason the design is worth attempting at all.

Break-glass: grey-clouded record straight to VIN

direct-origin · planned

Stands on: vin · Through: cloudflare-dns, tailscale

Kept deliberately modest. It survives the vendor edge and it does not survive the vendor's DNS, because with one nameserver provider nothing can. Listing it as though it covered both would be the most dangerous sentence in this file.

Hop Runs on Does When it goes
public-dns cloudflare-dns Resolves the published name to VIN's own address, with the Cloudflare proxy switched off. The name does not resolve — and this is the honest ceiling of the design, because this path was supposed to be the one that survives Cloudflare.
origin-ingress vin Answers the browser directly on :443 with its own Let's Encrypt certificate, with no vendor edge in front of it. There is nothing behind this path at all.
auth vin Authenticates as usual. Losing the vendor edge is not a reason to publish anything unauthenticated. Requests fail closed.
private-transport tailscale Carries the request to a backend on another host. VIN serves only what runs on VIN.

Failover

manual, 5 min Needs a DNS record changed.

None automatic. A person decides the vendor edge is the outage and switches the proxy off.

Never measured — this number is a prediction.

Certificate

Let's Encrypt, via Caddy on VIN, presented to The browser, directly. With the proxy off there is no Cloudflare certificate in front, so this one has to be valid for the public name on the day it is needed.

Key material: vin · Renewal: Automatic, by Caddy. It keeps renewing while the record is proxied, which is exactly what makes this path usable at short notice.

If this path is lost: The certificate is kept warm by the normal Caddy path. If both this and the Caddy path are withdrawn, renewal stops and this break-glass expires roughly 90 days later — which is the argument for never fully decommissioning Caddy on VIN.

Cutover — every step with the way back out beside it

  1. Prove the grey-clouded record works before needing it [owner, downtime: none if it works, one TTL if it does not]
    Switch one non-critical name to DNS-only for ten minutes and confirm it answers with a valid origin certificate.
    Verify: `openssl s_client` against VIN's address returns a certificate valid for the public name, issued by Let's Encrypt rather than Cloudflare.
    Undo: Switch the proxy back on. One record, one name.

Withdraw this path: Switch the Cloudflare proxy back on for the affected records. Nothing was installed and nothing was withdrawn, which is what makes this a break-glass rather than a migration.

Measurements

8 measured, 2 simulated
When Kind Mode Subject Result
reachability simulated status In the target posture status.collinscreations.co.uk is served in both required scenarios; in the current posture it is lost when VIN is.
failover simulated tunnel-home1 Predicted 30s for the edge to deregister a stopped connector and serve from the other. Unverified.
reachability measured homeassistant 200 to an anonymous request in 210ms
reachability measured tm 200 to an anonymous request in 248ms
reachability measured status 503 from the Cloudflare edge in 119ms
reachability measured myfinance 302 to an anonymous request in 77ms
reachability measured batteries 200 in 9364ms, and a 15s timeout on the immediately preceding run
reachability measured auth 403 from the Cloudflare edge in 481ms; no origin header of any kind
reachability measured jarvis 503 from the Cloudflare edge in 184ms
reachability measured ai 503 from the Cloudflare edge in 370ms

A simulation walks this file and proves the arithmetic. It has never found a connector that registered with the edge and then quietly stopped forwarding, and it never will.

Findings

Open questions