How this site is built.
The footer says “hand-built, no page builder” and means it. This page is the receipt: what the site is made of, where it runs, and how a change gets from my editor to the URL you’re reading — every layer of it self-hosted or hand-written.
The pages
Every page on hiten.dev is a hand-authored HTML file. There is no framework, no static-site generator, no build step — what you see in view source is what lives in the repository. That’s a deliberate constraint, not nostalgia: for a site this size a framework buys nothing except a toolchain to maintain, and a hand-written page keeps every byte accountable.
The type is three self-hosted variable fonts — Gabarito for display,
Hanken Grotesk for body text, and Newsreader italic for asides —
served as subsetted woff2 from this domain with no third-party font CDN. Critical CSS is
inlined in the head, the fonts are preloaded, and images are lazy-loaded WebP. The result is a
96 mobile Lighthouse performance score without a single trick that a
framework would have done “for free”.
Light and dark themes follow the system preference, every page carries skip links and passes
WCAG 2.2 AA checks, and the case-study lightboxes are pure CSS :target —
the only JavaScript on most pages is the analytics loader and a scroll-reveal observer.
The machine-readable layer
Alongside the human-readable pages there’s a full entity graph in JSON-LD — Person, WebSite, Article and SoftwareApplication nodes that cross-reference each other and Wikidata — plus llms.txt and llms-full.txt for AI assistants, a sitemap, Open Graph images, and speakable markup. If a crawler, an answer engine or an LLM wants to understand who I am and what I’ve built, the site hands it a structured answer rather than making it guess.
The pipeline
The source of truth lives on a Synology NAS in my home rack, versioned in a
self-hosted Forgejo instance running on the same box. Pushing to
master triggers a Forgejo Actions runner (also self-hosted, on the NAS) that rsyncs
the site over a WireGuard tunnel to an Oracle ARM free-tier VM, then restarts the
nginx container. Traefik terminates TLS with automatic certificates. From
git push to live is under a minute, and no code ever touches a third-party build service.
The same pattern serves the rest of my sites — including the Slipstream demo at tracker.hiten.dev and the Astro-based ask.hiten.dev — each with its own container behind the same edge.
Analytics without the creep: traffic is measured with self-hosted Umami — no cookies, no fingerprinting, no data leaving my infrastructure. Uptime is watched by a self-hosted Uptime Kuma instance that pushes alerts over ntfy.
The workflow
The site is also a working example of how I build now: AI-assisted with discipline.
Claude Code runs on a dedicated headless box on my network, each repository ships an
AGENTS.md with its own conventions, and well-scoped autonomous sessions get queued and
the diffs reviewed like pull requests. The judgement — architecture, positioning, what to
build at all — stays human; the typing is increasingly delegated.