Tailscale & Auth Review

Page layout

Read is the standard single column. Two only applies on desktop / landscape — phones stay single column rather than cramping the text.

Theme

Formatting style

Text size

17px

Line spacing

1.65

Body font

Heading font

Base style

Quotes & rules

Base style changes how headings, quotes, lists and rules are drawn. Themes set the palette; formatting style sets the shape.

Two-column needs a wider screen in landscape. Showing single column on this device.

Tailscale vs. the single password — recommendations and implementation

Question (Jeremy, Sep 21 2026): "If we have Tailscale set up and I install it on my phone, then we won't have to worry about passwords and it being accessible to the public. Is that correct? I'm just not sure the single password that we have going on is a good security measure or is enough."

Short answer: you're right, and it's more nuanced than a swap. Tailscale genuinely removes public exposure for private things — but your estate is two different kinds of site, and only one of them can go behind a tailnet. The single password is weak as configured today, but the weakness isn't "it's a password" — it's that it re-prompts you every 24 hours, which pushes you toward keeping things public to avoid the friction. Fix the friction and the password becomes fine. Full reasoning below.


1. The core correction: your phone on Tailscale does not hide a public site

This is the part that matters most, because it's the intuitive-but-wrong assumption.

Tailscale makes the person able to reach private hosts. It does not make a publicly-published site private. Those are independent:

So the plan isn't "install Tailscale, passwords become unnecessary." It's:

Move the private apps off the public internet entirely (tailnet-only), and then they need no password, because there is no public door to put one on.

That is a real and correct goal — and it's exactly what you already do for the stats/eink dashboards ("no login — network-level security"). The question is just which of your 53 Deploy sites plus Coolify apps can move, and which must stay public.


2. Why the single password is weak as it stands

I checked the live code rather than guessing. Three findings:

a) It re-prompts every 24 hours. SITE_AUTH_TTL defaults to 86400 seconds (deploy-api/app.py:381, comment literally says # 24h cookie). So every morning, on every device, you type it again. This is the friction that makes the whole gate feel not-worth-it — and it's the actual reason the estate drifted toward public-by-default.

b) One password opens all gated sites. Convenient, but it means a single leak — a shoulder-surf, a screenshot, a browser-sync mishap, one site's logs — opens health portals, financial plans, and client work together. No blast-radius containment.

c) It was protecting against a threat it doesn't beat. A password gate stops casual humans and honest crawlers. It does not stop an unauthenticated /api/data/<collection> call if a manifest marks a collection public, and it never stopped urlscan's crawler — that's how marble-tinsel-znwz (31 dollar figures) got archived. The archive got in while the data was public, before any gate existed.

What IS solid in there: bcrypt-hashed password, HMAC-signed cookie, httponly + secure + samesite=Lax, and lockout after 5 failures in 300s. The gate's mechanics are fine. It's the TTL and the single-secret-for-everything that need work.

Verdict: the password is not "not enough" for what it's guarding — but it is doing too many jobs at once, and it's over-frictioned in a way that causes the real problem.


3. The honest comparison

Ordered by how often you type something.


4. What should actually move behind Tailscale

Not everything can. Split your estate three ways:

A. Tailnet-only (no password needed) — private, single-user, no reason for public DNS:

B. Must stay public → keep a gate (with the TTL fixed):

C. Harmless → leave public, no gate:

Now the honest caveats about section A:


5. Recommended implementation

Phase 1 — immediate win, no new dependencies (~15 min).

  1. Change SITE_AUTH_TTL from 86400 to 31536000 (365 days) so the gate remembers your devices. One entry per device, ever. This alone fixes the friction that caused the exposure drift.
  2. Put the password in iCloud Keychain so even that single entry autofills.
  3. Verify with a fresh browser that the cookie persists past a day.

Phase 2 — Tailscale, for the sensitive tail (~45 min).

  1. Create the tailnet (personal account, free tier).
  2. Install on the OVH box and on the iPhone; confirm both peers see each other.
  3. Pick one app to move first — vitals is the best candidate (sensitive, yours only, low blast radius if it breaks). Bind it to the tailnet address, drop its public route.
  4. Confirm: reachable on the phone with Tailscale on; not reachable with it off; DNS no longer points at it publicly.
  5. Only then repeat for budget, bookoflife, vaultwarden, n8n.

Phase 3 — make it stick.

  1. Build security-pass.py (designed Sep 12, never built — still the missing piece). Runs after every build, prints PASS/WARN/FAIL, non-zero exit on FAIL so a new site can't ship public by accident.
  2. Wire it into the deploy and coolify-deploy skills as a required final step.
  3. Retire the Coolify UI noindex labels task if Tailscale removes those apps from public reach entirely — noindex becomes moot when there's no public listener.

6. Direct answers to what you asked


7. Recommendation in one line

Fix the 24-hour cookie today, put the health/finance/family apps on a tailnet over the next week, and let Tailscale carry the sensitive data while the password keeps covering the handful of things clients genuinely need to open.


8. What I need from you

Nothing is built yet — this is the plan. To start, say which:

Sources: live deploy-api/app.py (TTL + lockout constants), the Sep 12 security-pass research, and the Sep 20/21 exposure audit (53 sites, 9 here.now pages deleted, 133 CT subdomains probed).

# Tailscale vs. the single password — recommendations and implementation

**Question (Jeremy, Sep 21 2026):** *"If we have Tailscale set up and I install it on my
phone, then we won't have to worry about passwords and it being accessible to the public.
Is that correct? I'm just not sure the single password that we have going on is a good
security measure or is enough."*

**Short answer: you're right, and it's more nuanced than a swap.** Tailscale genuinely
removes public exposure for *private* things — but your estate is two different kinds of
site, and only one of them can go behind a tailnet. The single password *is* weak as
configured today, but the weakness isn't "it's a password" — it's that it re-prompts you
every 24 hours, which pushes you toward keeping things public to avoid the friction. Fix
the friction and the password becomes fine. Full reasoning below.

---

## 1. The core correction: your phone on Tailscale does not hide a public site

This is the part that matters most, because it's the intuitive-but-wrong assumption.

Tailscale makes *the person* able to reach private hosts. It does **not** make a
publicly-published site private. Those are independent:

- A site published on `mccloud.media` with public DNS keeps resolving for the whole
  internet, whether or not your phone is on the tailnet. Your phone joining the tailnet
  changes nothing about who else can reach it.
- Tailscale protects a service only when that service is **bound to the tailnet address
  and firewalled off from the public interface** — i.e. you deliberately take it off
  public DNS / out of the public reverse proxy.

So the plan isn't "install Tailscale, passwords become unnecessary." It's:

> Move the private apps **off the public internet entirely** (tailnet-only), and then
> they need no password, because there is no public door to put one on.

That is a real and correct goal — and it's exactly what you already do for the stats/eink
dashboards ("no login — network-level security"). The question is just which of your 53
Deploy sites plus Coolify apps can move, and which must stay public.

---

## 2. Why the single password is weak as it stands

I checked the live code rather than guessing. Three findings:

**a) It re-prompts every 24 hours.** `SITE_AUTH_TTL` defaults to `86400` seconds
(`deploy-api/app.py:381`, comment literally says `# 24h cookie`). So every morning, on
every device, you type it again. This is the friction that makes the whole gate feel
not-worth-it — and it's the actual reason the estate drifted toward public-by-default.

**b) One password opens all gated sites.** Convenient, but it means a single leak — a
shoulder-surf, a screenshot, a browser-sync mishap, one site's logs — opens
health portals, financial plans, and client work together. No blast-radius containment.

**c) It was protecting against a threat it doesn't beat.** A password gate stops casual
humans and honest crawlers. It does not stop an unauthenticated `/api/data/<collection>`
call if a manifest marks a collection `public`, and it never stopped urlscan's crawler —
that's how `marble-tinsel-znwz` (31 dollar figures) got archived. The archive got in
*while the data was public*, before any gate existed.

**What IS solid in there:** bcrypt-hashed password, HMAC-signed cookie, `httponly` +
`secure` + `samesite=Lax`, and lockout after 5 failures in 300s. The gate's *mechanics*
are fine. It's the TTL and the single-secret-for-everything that need work.

**Verdict:** the password is not "not enough" for what it's guarding — but it is doing
too many jobs at once, and it's over-frictioned in a way that causes the real problem.

---

## 3. The honest comparison

Ordered by how often you type something.

- **Tailnet-only (no gate).** Zero typing, ever. Strongest option available — there
  literally is no public listener to attack. Requires the device to be on Tailscale.
- **Password + 365-day device cookie.** Type once per device, then never. Same
  cryptography as today, just not expiring weekly. Low-friction enough to actually keep.
- **Password + 24h cookie (today).** Type daily per device. This is the one causing pain.
- **Username + password.** More friction, negligible gain for a one-person estate.
- **Magic link.** Email round-trip every time; adds a dependency and a phishable link.
- **URL token bookmark.** Zero typing, but a leaked URL *is* the access — no revocation
  without rotating. Fine only for harmless pages.

---

## 4. What should actually move behind Tailscale

Not everything can. Split your estate three ways:

**A. Tailnet-only (no password needed)** — private, single-user, no reason for public DNS:
- `vitals` — health data
- `budget` — personal finances
- `bookoflife` — family legacy/estate
- `debra` (health portal) and other medical portals
- `vaultwarden` — password manager (should never have been name-discoverable)
- `n8n`, `coolify`, `comms` — admin tooling
- `stats`, `apis`, `eink`, `pc-health`, `hermes-monitor` — already network-level, just formalize

**B. Must stay public → keep a gate (with the TTL fixed)**:
- `c2c-halloween`, `permits`, client previews — Billy/Amara, Ryan, Gary need them without
  installing anything
- Anything a client, provider, or family member opens on a device you don't control

**C. Harmless → leave public, no gate**:
- weather pages, model-news digests, marketing mockups, previews, `brief`

Now the honest caveats about section A:

- **Tailscale is a dependency.** If the tailnet is down, the app is unreachable — including
  by you. CoS (Tailscale's coordination server) outages have happened. Not fatal for a
  budget dashboard; think harder for anything you might need in an emergency.
- **Every device needs the client.** Your iPhone is easy. Guests, clients, a random work
  laptop, a hospital tablet — none of them get in. That's why section B exists.
- **Cost/rules:** free tier covers 3 users / 100 devices, personal use. Fine here.
- **Public DNS still exposes the names.** CT logs already show 133 subdomains. Moving to
  tailnet-only means the *name* resolves nowhere useful, but the name itself stays known.
  Removing the DNS record entirely is the cleaner version if you want the names gone too.

---

## 5. Recommended implementation

**Phase 1 — immediate win, no new dependencies (~15 min).**
1. Change `SITE_AUTH_TTL` from `86400` to `31536000` (365 days) so the gate remembers
   your devices. One entry per device, ever. This alone fixes the friction that caused
   the exposure drift.
2. Put the password in iCloud Keychain so even that single entry autofills.
3. Verify with a fresh browser that the cookie persists past a day.

**Phase 2 — Tailscale, for the sensitive tail (~45 min).**
1. Create the tailnet (personal account, free tier).
2. Install on the OVH box and on the iPhone; confirm both peers see each other.
3. Pick **one** app to move first — `vitals` is the best candidate (sensitive, yours only,
   low blast radius if it breaks). Bind it to the tailnet address, drop its public route.
4. Confirm: reachable on the phone with Tailscale on; **not** reachable with it off; DNS
   no longer points at it publicly.
5. Only then repeat for `budget`, `bookoflife`, `vaultwarden`, `n8n`.

**Phase 3 — make it stick.**
1. Build `security-pass.py` (designed Sep 12, never built — still the missing piece).
   Runs after every build, prints PASS/WARN/FAIL, non-zero exit on FAIL so a new site
   can't ship public by accident.
2. Wire it into the `deploy` and `coolify-deploy` skills as a required final step.
3. Retire the Coolify UI noindex labels task if Tailscale removes those apps from public
   reach entirely — noindex becomes moot when there's no public listener.

---

## 6. Direct answers to what you asked

- **"Then we won't have to worry about passwords and it being accessible to the public"** —
  Correct *for apps we move off public DNS*. Incorrect if we just install Tailscale on
  your phone and change nothing else; that hides nothing.
- **"Is the single password enough?"** — For public-facing client previews, yes, once the
  TTL is fixed. For health, financial, and family data, no — it's one secret guarding too
  much, and those belong behind the tailnet where no password is needed at all.
- **The real fix is both:** Tailscale for what's private, a remembered password for what
  must stay public. Neither alone covers your estate.

---

## 7. Recommendation in one line

Fix the 24-hour cookie today, put the health/finance/family apps on a tailnet over the
next week, and let Tailscale carry the sensitive data while the password keeps covering
the handful of things clients genuinely need to open.

---

## 8. What I need from you

Nothing is built yet — this is the plan. To start, say which:
- **"Do phase 1"** — the TTL fix, ~15 min, no new accounts.
- **"Start Tailscale"** — I'll walk the tailnet creation, then move `vitals` first.
- **"Do both"** — phase 1 now, then one app onto the tailnet as a proof.

Sources: live `deploy-api/app.py` (TTL + lockout constants), the Sep 12 security-pass
research, and the Sep 20/21 exposure audit (53 sites, 9 here.now pages deleted, 133 CT
subdomains probed).

Reader controls

C
Contents panel
N
Notes panel
1 2 3 4
Layout — Read / Two / Wide / Full
R
Read → Raw → Split
T
Cycle theme (Shift+T goes back)
+ / −
Text size
F
Fullscreen
Z
Focus mode — dims the toolbar
Ctrl/⌘ P
Print or save as PDF
?
This panel

To highlight: select text in the document, then choose a colour or add a note. Your theme, size, fonts, layout and panel state are remembered on this device for this document.