What changed, and why
The Two Ls site is one static page. public/index.html is the whole thing, icons aside; there is no build and there are no tests. Hosting it still took a container: nginx wrapped around public/, built by CI, pushed to ghcr.io, pulled by a k8s pod. This PR retires that whole apparatus. Vercel's git integration serves public/ straight from the repo, so main is production and any PR gets a preview URL for free.
Four files leave. Dockerfile, nginx.conf, .dockerignore, and the whole CI workflow go, while a five-line vercel.json arrives in their place. The infra half of the move, meaning the DNS flip and the k8s stack retirement, is mseeks/zo#21.
One behavior changes on purpose. Today www.2ls.tech serves the page directly. After cutover it will redirect to the apex instead — not automatic platform behavior, but the dashboard's Redirect-to setting, configured when the domains are attached (mseeks/zo#21 carries the step). Apex-as-canonical matches what playeverwhen.com already does, though Vercel's own docs lean the other way (www primary).
vercel.json: nginx's job in five lines
nginx did five things for this site. One of them moves into vercel.json. Three turn out to be platform behavior. The last had no job left:
The whole file: serve public/, clean URLs.
| nginx rule | where it lives now |
|---|---|
try_files $uri $uri.html $uri/ (extension-less URLs) | cleanUrls: true |
Cache-Control: no-cache on the site content (both content locations) | Vercel's static default (public, max-age=0, must-revalidate) makes browsers revalidate — same effect |
gzip on + types | edge compression (gzip and brotli), no config |
.webmanifest served as application/manifest+json | observed Vercel behavior (docs are silent; live Vercel sites serve it correctly) — on the cutover checklist |
/healthz for the k8s probes | dropped — no pod, no probes |
The container path, retired whole
The deleted CI workflow had exactly one job. It built the nginx image and pushed ghcr.io/mseeks/2ls.tech, a :latest and a :<sha>, gated on nothing because the repo has nothing to gate on. Its own comment said as much: "the files under public/ are the artifact." The one consumer of those images was the k8s Deployment pulling :latest, retired in mseeks/zo#21. So the workflow file goes entirely rather than shrinking to an empty jobs: map. A repo with no checks now honestly has no CI.
Dockerfile (14 lines of nginx + COPY public/), the 39-line nginx.conf, and .dockerignore go with it.
The Serving section now tells the Vercel story.
README.md · 34 lines
⋯ 25 lines hidden (lines 1–25)
How to verify it
There is nothing to run pre-merge beyond vercel.json parsing as JSON (it does); the repo has no suite, and this PR does not touch public/.
The real checks come after cutover, against the live hosts. The apex should serve the page with a revalidating cache header. www.2ls.tech should redirect to the apex. /site.webmanifest should come back as application/manifest+json. And /index.html should 308 to /, the cleanUrls fingerprint. The cutover ordering itself (Vercel project and both domains first, DNS second, namespace deletion last) lives in mseeks/zo#21; merging this PR alone changes nothing live.