This repo packages our TanStack Start Nitro SSR web app as a Unikernel for Unikraft Cloud, with a matching Docker/Compose flow for local smoke tests. The monorepo hosts the demo UI in apps/web plus shared code in packages/*, with infrastructure assets under infrastructure/.
The infrastructure/kraftcloud tree packages the TanStack Start SSR demo (apps/web) so it can be previewed locally with Docker Compose and then pushed to the exact same container image on Unikraft Cloud. Follow this guide to ship the Nitro server behind a Kraft-managed TLS endpoint that matches the domain configured in your demo (VITE_SERVER_URL).
- One source of truth:
Dockerfile.webbuilds the TanStack Start SSR runtime that powers local Compose, Kraft Cloud, and thepnpm --filter @iapacte/apps-web devworkflow. - Deterministic settings:
.envfeeds both Docker Compose and Kraft Cloud so the publicVITE_SERVER_URLalways matches the hostname you deploy (important when routing the chat UI + SSR over the same domain). - Portable deployment: the Kraftfile reuses the exact build context from the monorepo root, exposes TLS on port
443, and scales to zero between live demos.
apps/web– TanStack Start SSR demo app used in the council storyline.packages/*– shared UI and logic consumed byapps/web.Dockerfile.web– multi-stage build for the Nitro SSR server published to Kraft Cloud.docker-compose.yaml– local validation stack that reuses the same Dockerfile.infrastructure/kraftcloud/web/– Kraft manifest plus optional Caddy rootfs assets.infrastructure/kraftcloud/.env.example– shared environment template (VITE_SERVER_URL,NODE_ENV,PORT,NITRO_PORT).
-
Install Docker Desktop (Compose is bundled) and verify with
docker --version && docker compose version. -
Install Nix (see zero-to-nix) and enter the dev shell for consistent
pnpm,kraftkit, andopenfga-cliversions:nix develop # or nix develop -c zsh
Export your Unikraft Cloud token and target metro before deploying:
export UKC_TOKEN="<your-kraftcloud-token>"
export UKC_METRO=fraUse Docker Compose to confirm the SSR build boots with your .env configuration.
cp infrastructure/kraftcloud/.env.example infrastructure/kraftcloud/.env
docker compose \
-f infrastructure/kraftcloud/docker-compose.yaml \
--env-file infrastructure/kraftcloud/.env \
up --buildThe TanStack Start server listens on http://localhost:3000 so you can verify the storyline locally before hitting Kraft Cloud.
-
Copy the env file and set
VITE_SERVER_URLto the hostname you plan to use on Kraft Cloud (e.g.https://demo.fra.unikraft.app) without opening an editor:cp infrastructure/kraftcloud/.env.example infrastructure/kraftcloud/.env export SUBDOMAIN=iapacte-demo # pick any DNS-safe slug export UKC_METRO=fra # change if you deploy elsewhere export DOMAIN="$SUBDOMAIN.$UKC_METRO.unikraft.app" perl -i -pe "s|^VITE_SERVER_URL=.*|VITE_SERVER_URL=https://$DOMAIN|" infrastructure/kraftcloud/.env
Re-run the
exportlines whenever you open a new shell; onlyVITE_SERVER_URLis stored inside.env. -
Load the env vars whenever you deploy:
set -a; . infrastructure/kraftcloud/.env; set +a
-
(Optional) warm up the build output to catch failures early:
pnpm turbo run build --filter=@iapacte/apps-web
Run the deployment from the monorepo root so the Kraftfile can see Dockerfile.web. Reuse the SUBDOMAIN/UKC_METRO exports from the preparation step (export them again if you started a new shell).
kraft cloud deploy \
--kraftfile infrastructure/kraftcloud/web/Kraftfile \
--subdomain "$SUBDOMAIN" \
-p 80:443/http+redirect \
-p 443:3000/http+tls \
-M 1024M \
.--subdomainprovisionshttps://$SUBDOMAIN.$UKC_METRO.unikraft.appautomatically; replace with--domain your-domain.comwhen delegating a custom domain.- The TLS endpoint on
443is whatapps/webexpects; updatingVITE_SERVER_URLkeeps client + server on the same origin so cookies and SSR data stay in sync.
If the service already exists, redeploy in-place instead of grabbing a new subdomain:
SERVICE_NAME=$(kraft cloud service ls --metro "$UKC_METRO" | awk '/iapacte-web/{print $1; exit}')
set -a; . infrastructure/kraftcloud/.env; set +a
kraft cloud deploy \
--kraftfile infrastructure/kraftcloud/web/Kraftfile \
--service "$SERVICE_NAME" \
--rollout remove \
-M 1024M \
.Skip -p/--subdomain flags while redeploying; the existing service retains its ports and hostname.
-
View running services/instances:
kraft cloud service ls --metro $UKC_METROandkraft cloud instance ls --metro $UKC_METRO. -
Tail logs:
kraft cloud instance logs <instance> --metro $UKC_METRO. -
Remove old artifacts when you are done rehearsing:
kraft cloud service remove <service> --metro $UKC_METRO. -
When the endpoint is live, verify health from your laptop or CI:
curl -i "https://$DOMAIN/health"(Replace
/healthwith whichever Nitro route you expose.)
- Unikraft CLI install guide: https://unikraft.org/docs/cli/install
- Kraft Cloud product docs: https://unikraft.org/docs/cloud/
- TanStack Start docs: https://tanstack.com/start/latest