Vite: allow tailnet hostnames so dev overlay can serve via reverse proxy #117

Open
opened 2026-05-05 12:46:42 +00:00 by forgejo_admin · 0 comments
Contributor

Type

Feature

Lineage

Discovered while bringing up the new pal-e-dev dev overlay (ldraney/pal-e-deployments#151 / PR #152). When traffic from https://pal-e-dev.tail5b443a.ts.net reached Vite via the Tailscale ingress + Service, Vite returned HTTP 403 because the unfamiliar Host header isn't in server.allowedHosts. Same blocker will hit any future dev overlay (*-dev.tail5b443a.ts.net).

Already applied locally on branch iterate-2026-05-04 and verified working — this PR commits the fix to main.

Repo

ldraney/pal-e-app

User Story

As Lucas (developer)
I want Vite to accept any *.tail5b443a.ts.net Host header
So that any dev overlay funnel hostname works without a config change per overlay

Context

Vite 6 ships with a stricter server.allowedHosts default than older versions: it only allows localhost and the bind-address Host. Any reverse-proxy (k8s ingress, Tailscale funnel, etc) appears to Vite as an unknown host and gets 403'd. This is invisible during local dev (where Host always matches localhost) but breaks the moment Vite sits behind a proxy — exactly our dev overlay pattern.

Direct verification 2026-05-05: curl -H "Host: pal-e-dev.tail5b443a.ts.net" http://<pod-ip>:5173/ returned HTTP/1.1 403 Forbidden, while wget http://localhost:5173/ from inside the pod returned proper SvelteKit HTML. Confirms the 403 originates inside Vite.

File Targets

Files to modify:

  • vite.config.ts -- add server: { allowedHosts: ['.tail5b443a.ts.net'] } (leading dot wildcards subdomains)

Files to NOT touch:

  • package.json -- vitest is already declared; no dep changes needed

Acceptance Criteria

  • vite.config.ts includes server.allowedHosts allowing .tail5b443a.ts.net
  • After dev pod restart, curl -H "Host: pal-e-dev.tail5b443a.ts.net" http://<pod-ip>:5173/ returns 200 with HTML
  • https://pal-e-dev.tail5b443a.ts.net/ loads the SvelteKit app
  • Prod build (npm run build) still succeeds — allowedHosts is dev-only

Test Expectations

  • Manual smoke: kubectl -n pal-e-app delete pod -l app=pal-e-app-dev then curl -sI https://pal-e-dev.tail5b443a.ts.net/ returns 200
  • Manual hot-reload: edit +page.svelte after fix, change appears via dev URL in <2s

Constraints

  • Use leading-dot wildcard (.tail5b443a.ts.net) so all current and future dev overlays inherit the allowance — avoids per-overlay config drift
  • Do not weaken to allowedHosts: true (that would allow anything, including DNS rebinding attacks against any local Vite)

Checklist

  • PR opened
  • Vite serves correctly via dev URL
  • No unrelated changes
  • Commit notes the dev-overlay context
  • ldraney/pal-e-deployments #151 -- the dev overlay that surfaced this
  • ldraney/pal-e-deployments #153 -- the parallel CORS fix on the backend (just merged)
  • pal-e-app -- the project this fixes
### Type Feature ### Lineage Discovered while bringing up the new `pal-e-dev` dev overlay (ldraney/pal-e-deployments#151 / PR #152). When traffic from `https://pal-e-dev.tail5b443a.ts.net` reached Vite via the Tailscale ingress + Service, Vite returned HTTP 403 because the unfamiliar `Host` header isn't in `server.allowedHosts`. Same blocker will hit any future dev overlay (`*-dev.tail5b443a.ts.net`). Already applied locally on branch `iterate-2026-05-04` and verified working — this PR commits the fix to main. ### Repo `ldraney/pal-e-app` ### User Story As Lucas (developer) I want Vite to accept any `*.tail5b443a.ts.net` Host header So that any dev overlay funnel hostname works without a config change per overlay ### Context Vite 6 ships with a stricter `server.allowedHosts` default than older versions: it only allows `localhost` and the bind-address Host. Any reverse-proxy (k8s ingress, Tailscale funnel, etc) appears to Vite as an unknown host and gets 403'd. This is invisible during local dev (where Host always matches localhost) but breaks the moment Vite sits behind a proxy — exactly our dev overlay pattern. Direct verification 2026-05-05: `curl -H "Host: pal-e-dev.tail5b443a.ts.net" http://<pod-ip>:5173/` returned `HTTP/1.1 403 Forbidden`, while `wget http://localhost:5173/` from inside the pod returned proper SvelteKit HTML. Confirms the 403 originates inside Vite. ### File Targets Files to modify: - `vite.config.ts` -- add `server: { allowedHosts: ['.tail5b443a.ts.net'] }` (leading dot wildcards subdomains) Files to NOT touch: - `package.json` -- vitest is already declared; no dep changes needed ### Acceptance Criteria - [ ] `vite.config.ts` includes `server.allowedHosts` allowing `.tail5b443a.ts.net` - [ ] After dev pod restart, `curl -H "Host: pal-e-dev.tail5b443a.ts.net" http://<pod-ip>:5173/` returns 200 with HTML - [ ] `https://pal-e-dev.tail5b443a.ts.net/` loads the SvelteKit app - [ ] Prod build (`npm run build`) still succeeds — `allowedHosts` is dev-only ### Test Expectations - Manual smoke: `kubectl -n pal-e-app delete pod -l app=pal-e-app-dev` then `curl -sI https://pal-e-dev.tail5b443a.ts.net/` returns 200 - Manual hot-reload: edit `+page.svelte` after fix, change appears via dev URL in <2s ### Constraints - Use leading-dot wildcard (`.tail5b443a.ts.net`) so all current and future dev overlays inherit the allowance — avoids per-overlay config drift - Do not weaken to `allowedHosts: true` (that would allow anything, including DNS rebinding attacks against any local Vite) ### Checklist - [ ] PR opened - [ ] Vite serves correctly via dev URL - [ ] No unrelated changes - [ ] Commit notes the dev-overlay context ### Related - `ldraney/pal-e-deployments #151` -- the dev overlay that surfaced this - `ldraney/pal-e-deployments #153` -- the parallel CORS fix on the backend (just merged) - `pal-e-app` -- the project this fixes
Commenting is not possible because the repository is archived.
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/pal-e-app#117
No description provided.