The hosting stack behind webhost24.in: Astro 7, Svelte 5, and the Palitana CDN
The exact stack that powers webhost24.in: Astro 7 + Svelte 5 + Tailwind 4 + a per-app OG image generator. The full architecture, build pipeline, and deployment story.
The R221 marketing site (this site you’re reading) is built on the following stack. This post is the canonical source of truth for the architecture.
Frontend
- Astro 7 as the meta-framework. Runs in SSR mode
(
output: "server") via the@astrojs/nodestandalone adapter so every response is fresh (no stale prerendered HTML). The same Docker image can run on any container host. - Svelte 5 for the small set of interactive islands (mobile menu, cookie banner, sticky header, billing cycle toggle). Astro components are HTML by default; Svelte is opt-in per island.
- Tailwind 4 via the Vite plugin (the new style).
Brand palette is intentionally small - primary
#002071, natural-dark#1F1F1F, natural-light#F1F1F1, secondary#FFFF00. All colour tokens are declared once inglobals.cssunder the@themeblock; no tints or shades are introduced outside the locked tokens (per AGENTS.md §6). - bits-ui for the small set of unstyled accessible primitives (accordion, sheet/dialog, switch, tabs, tooltip, select). Drop-in replacement for the R220 Radix UI setup.
Per-app OG image generator
A custom Node + sharp script (scripts/build-app-og-pngs.mjs)
generates one 1200x630 PNG per app MDX file at prebuild
time. Each PNG uses the app’s brand colour as the
background + the app title + a 60-char wrap of the
excerpt as the foreground. Wired into the prebuild script
chain so the PNGs are regenerated before every
astro build.
Build pipeline
The npm run build command is a 3-step chain:
prebuild- runsbuild-og-png.mjs+build-llms-txt.mjsbuild-app-og-pngs.mjs.
build- runsastro build(renders the static HTML- the JS chunks for the islands).
start- the dev server (not part of CI; for localnpm run devonly).
The output is a static dist/client/ (run du -sh dist/client
in the repo to see the current size) + a server entrypoint at
dist/server/entry.mjs that runs on port 2828 via
@astrojs/node standalone.
Deployment
The Docker image (single-stage, alpine-based) is built
from the repo’s Dockerfile. The build step does npm ci, then runs npm run build. The runtime step copies
dist/server/entry.mjs + dist/client/ into the
container image and runs node ./dist/server/entry.mjs.
The same image is deployed to Palitana on a Kubernetes
cluster managed by our ops team. Health-checks hit
/healthz (returns {status: "ok"}). Cache-Control
headers are set in the Astro middleware (s-maxage 7d for
/fonts/, s-maxage 1d for /apps/ + /brand/).
Why this stack
Astro ships 0 JS by default; only the islands contribute. Our largest island bundle is the cookie banner (~15 KB gzipped). Total JS payload across the public surface is ~30 KB gzipped, which is well under the 50 KB per-page budget from spec §9.
Svelte 5’s $state / $derived reactivity is small
enough to render in a few KB gzipped per island. Run
npm run build && du -h dist/client/_astro/*.js against the
repo to see the current per-island sizes.