Astro (static)
Use this when output: "static" (or pages are prerendered). The HMAC secret is only needed on the machine that runs astro build—usually CI, not developers’ laptops with prod keys.
Project layout (suggested)
Section titled “Project layout (suggested)”src/ lib/ rendorix/ signUrl.ts # canonical + HMAC — server/build only pages/ gallery/ [slug].astro # getStaticPaths + signed src per item content/ # optional: MD with frontmatter asset keysastro.config.mjsKeep signing out of client: islands and out of public import.meta.env—only non-secret values like the image host may use PUBLIC_ prefixes.
Environment variables and secrets in CI
Section titled “Environment variables and secrets in CI”- In GitHub Actions (or your CI), add
RENDORIX_HMAC_SECRETandRENDORIX_BASE_URLas encrypted secrets. - Export them before
npm run buildso Node can readprocess.envinsignUrl.tsduring the static build. - Do not add the HMAC secret to Cloudflare Pages build env for a pure static site unless that build is trusted and scoped to non-prod as appropriate.
Local dev: use .env (gitignored) with a dev key and staging distribution, or mock URLs that skip signing if your local edge allows it (not for production testing).
Generating stable image URLs in content
Section titled “Generating stable image URLs in content”Option A — frontmatter + helper (src/pages/post/[slug].astro). The snippet assumes a blog content collection; adapt getCollection to your own schema.
---import { getCollection } from "astro:content";import { signRendorixUrl } from "../../../lib/rendorix/signUrl";
export async function getStaticPaths() { const posts = await getCollection("blog"); return posts.map((post) => ({ params: { slug: post.slug }, props: { title: post.data.title, heroSrc: signRendorixUrl(`/assets/${post.data.coverKey}`, { p: "hero", }), }, }));}const { title, heroSrc } = Astro.props;---<article> <h1>{title}</h1> <img src={heroSrc} alt="" width="1200" height="630" loading="eager" /></article>Option B — Markdown / MDX — resolve coverKey in a layout that calls the same helper (keep the helper import on the server build side only).
Stability: the same logical image should map to the same URL string across builds if exp is fixed or derived from content version—otherwise you bust CDN cache unnecessarily (Caching).
Build and preview commands
Section titled “Build and preview commands”# CIexport RENDORIX_BASE_URL="https://img.example.com"export RENDORIX_HMAC_SECRET="…" # from secrets storenpm run build
# Local preview of static outputnpm run previewastro preview serves the built HTML; image requests still go to real CloudFront—use staging credentials and short exp when testing.
Caveats
Section titled “Caveats”- Rotating images without rebuild: static HTML holds old signed links until you redeploy or use long
exp+ TTL policy. - Per-user images in static HTML is awkward—use Astro (SSR) or a small API the client calls for fresh URLs.