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. Builds the site to
static HTML via
output: "static". The@astrojs/nodeadapter serves the build in standalone mode so 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-color palette: brand primary
#002071, secondary#FAA21B, success#16A34A, error#DC2626. All tokens declared once in globals.css. - 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/ (~2.9 MB across
70+ HTML pages + 12 brand assets + 17 per-app OG PNGs)
- a server entrypoint at
dist/server/entry.mjsthat runs on port 2828 via@astrojs/nodestandalone.
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 4-5 KB gzipped per island. The old
React 19 + Radix UI combo in the R220 setup shipped ~120
KB gzipped of JS. The 4x reduction is the biggest perf
win of the R221 cut.