Colophon

Colophon

Updated: 2026-05-17

This page — how the site is built, deployed, and operated. Every component is open-source or free-tier; the whole stack runs on a personal Cloudflare account.

Stack

FrameworkAstro 5 — static site generator + content collections (markdown/MDX)
RuntimeCloudflare Workers — single worker (khavan) serves HTML + API + cron
Static deliveryWorkers Assets binding — no Pages, no outer CDN
SearchPagefind (keyword) + Vectorize (semantic) — toggle at /en/search/
Embeddingsbge-m3 via Workers AI — 1024-dim multilingual
RAG / "Ask the blog"Vectorize top-5 → Bedrock Claude Opus 4.7 via OIDC federation

Storage

D1 khavan-subscriberssubscribers + digests + contacts + post views + AI cache + webmentions + intel hub
KV OIDC_CREDS_CACHEBedrock temp creds (45-min TTL) to avoid STS exchange per call
R2 khavan-backupsWeekly D1 snapshot (NDJSON.gz, 84-day retention)
Vectorize khavan-posts1,500+ vector chunks indexed from post archive

AI integrations

  • Workers AI bge-m3 — embed query for semantic search + RAG (free tier)
  • Workers AI Llama 3.1 — fallback if Bedrock fails
  • AWS Bedrock Claude Opus 4.7 — primary for RAG + post summarize
  • OIDC federation — Worker mints JWT, AWS STS exchanges → temp creds. No long-lived AWS key in code. Details in this post.
  • AI Gateway — caches Bedrock calls for 24h, observability
  • Daily budget cap 500 calls/UTC day, kill switch on abuse

Cron schedule

  • 0 */6 * * * — Intel Hub ingest RSS + LLM analyze (every 6h)
  • 0 2 * * SUN — Weekly digest + outgoing webmentions (Sun 02:00 UTC)
  • 0 3 * * SUN — D1 snapshot → R2 (Sun 03:00 UTC)
  • 0 9 * * * — GitHub Actions daily rebuild for drip-publish (Daily 09:00 UTC)

Security

  • HSTS preload + DNSSEC active + DMARC p=reject
  • Cloudflare WAF 5 custom rules (Free plan max), Bot Fight Mode bypasses verified bots
  • Rate limit 5 req/10s at edge + per-IP sliding window at app layer
  • Cloudflare Access JWT gates /admin/* + email allowlist
  • Worker Observability 100% sampling — query via Analytics Engine SQL API
  • OIDC keys rotated via wrangler secret, never in git

Design

  • Tokens: primary orange #f48120 (Cloudflare brand reference) + ink/muted hierarchy
  • Font: Inter variable, self-hosted woff2 (latin + vietnamese subsets, preloaded per locale)
  • Theme: light/dark + system, theme-color meta for mobile browser chrome
  • OG image per-post: SVG template rendered via resvg WASM → 1200×630 PNG

Open source acknowledgments

Direct dependencies in package.json:

Design inspiration: blog.cloudflare.com. Color contrast tuned for WCAG AA.

Hosting cost

Entirely on Cloudflare Workers Free Plan:

  • Workers: 100k req/day free → site uses < 5%
  • D1: 5 GB + 5M reads/day → 0.7 MB used, ~1000 reads/day
  • KV: 100k reads/day → tens of reads/day for OIDC cache
  • R2: 10 GB + 1M Class A ops/month → hundreds of ops/month
  • Vectorize: 5M queried dims/month → ~100k/month
  • Workers AI: free tier neurons/day → enough

Bedrock (AWS) pay-per-token, daily budget capped at 500 calls. Realistic spend < $5/month.

Source

Source code public at github.com/vanhoangkha/khavan. CI: GitHub Actions → wrangler deploy. Each push lives within ~3 minutes.

License

  • Content: All Rights Reserved. Short quotes + link OK; reuse requires permission. See terms.
  • Code snippets in posts: MIT license.
  • Repository code: no public license yet — read OK, fork OK, commercial use requires contact.
  • AI training: NOT permitted. Content-Signal directives in /robots.txt.

Contact

khavan.work@gmail.com · LinkedIn · GitHub