server

One file. Zero dependencies.

A Node web server for a single-page app that does what a static host does — safe paths, brotli, caching, SPA fallback, a PWA — and scores 100 in every Lighthouse category. Nothing to install: one command serves any folder.

npx @labs_kai/server dist
# → http://127.0.0.1:2211

View on GitHub What it does

Ask this server something

Each answer comes live from the server hosting this page. The line under the status is what simple-server answers, so here the two should agree.This copy is on a static host, so the answers below are the host's. The line under the status is what simple-server answers when you run npm start.

– ms

200 OK

With npm start: 200, the app shell

content-type
text/html; charset=utf-8
cache-control
no-cache
content-encoding
br
vary
Accept-Encoding
etag
W/"…"
x-content-type-options
nosniff
x-frame-options
SAMEORIGIN

What a static host does.

Everything a good static host does and a bare http.createServer doesn't. Two hundred lines, read in ten minutes: lib/simple-server.js. Its tests run over a real socket: npm test.

Safe paths
Every URL resolves inside public/. ../, encoded dots, doubled slashes and dotfiles can't escape it; /.well-known/ can.
SPA fallback
Extension-less paths get index.html with a 200, so client-side routing works. Unknown /api/* paths and non-HTML requests get a real 404.
Caching that doesn't bite
HTML, sw.js and the manifest: no-cache. Assets: a day. Fingerprinted assets: a year, immutable. Weak ETags and Last-Modified turn repeat visits into 304s.
Compression
Brotli or gzip for text over 1 KB, with Vary: Accept-Encoding. Images and fonts are left alone.
Right types
Content-Type with charset for text, application/manifest+json, font/woff2, image/x-icon, application/wasm.
Range requests
<video> and <audio> seek with 206 Partial Content.
Security headers
X-Content-Type-Options, Referrer-Policy, X-Frame-Options; HSTS when the connection is TLS.
Never a crash
Malformed URLs are a 400, other methods a 405, a file that disappears mid-request a 404, anything unexpected a 500. The process stays up.
Health and routes
GET /api/health answers with uptime and request count; add your own JSON routes in a line each.
HTTPS when you want it
npm run cert makes a localhost pair and the server switches to HTTPS. Behind nginx or Caddy, leave it off.

Measured in your browser.

Not a claim: this page load, read from the Performance API and rendered by minim. It holds on any host.

– KB

over the wire for the whole page: – KB of HTML, – smaller compressed.

JS, CSS and font requests
0
First paint
–
Protocol
–

A PWA that updates itself.

The build hashes every file it ships into the service worker, so each deploy is a new cache version. The shell, the not-found page and the icons are precached at install; assets are served from cache and refreshed in the background; a navigation that can't reach the network gets the shell, so the app opens offline.

When a new version is installed behind the page, it waits. The page shows a prompt, and one tap swaps the worker and reloads. Because the server sends sw.js and the manifest with no-cache, browsers see a deploy at once instead of a day later.

The manifest has an id, maskable icons, a shortcut and screenshots, so it installs cleanly on Android, desktop Chrome, Edge and Safari.

This install

Service worker
checking
Cache version
–
Network
online
Installed as an app
no

Make it yours.

Your app

Drop your build into public/. index.html is the shell every client-side route falls back to, 404.html the not-found page. Fingerprint your assets (app.3f9c2a1b.js) and they are cached for a year. Everything else is an environment variable.

PORT=8080 HOST=0.0.0.0 npm start
npm run dev          # verbose, restarts on change
npm run cert         # then npm start speaks https
npm run build        # site/ → public/ (this page, the service worker)

Your agent

The repository is laid out for coding agents as much as for people. AGENTS.md explains the layout, the rules and the commands; skills/simple-server teaches an agent to build and verify a page the way this one was built; npm run check is the whole verification — tests, a static preflight of the pages, Lighthouse against the real server. And the server speaks MCP: started with MCP=1, an agent can list and read what it serves and see exactly how it answers any path.

npx skills add hertonwork/server
npm run check        # tests + preflight (+ Lighthouse)
MCP=1 npm start
claude mcp add --transport http server \
  http://127.0.0.1:2211/mcp