A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 79 lines 4.5 kB View raw View rendered
1# SP7 — Deploy (Cloudflare) 2 3- **Date:** 2026-06-08 4- **Status:** Deploy-ready + edge-verified locally. The final `wrangler deploy` runs on the 5 owner's Cloudflare account. 6- **Goal (brief §8, §9.8):** Deploy to a free host. Cloudflare. 7 8## Decision (0009) 9 10Deploy to **Cloudflare Workers (Static Assets)** via `@astrojs/cloudflare` v13 — the 11modern Astro Cloudflare target (Cloudflare is folding Pages into Workers + Static Assets; 12the adapter no longer emits a Pages `_worker.js`). Same Cloudflare account + custom domain 13as "Pages"; the read-through renderer (SP4) runs as the Worker, static assets (landing, 14editor shell, fonts, `client-metadata.json`) served from the edge cache. 15 16- `nodejs_compat` (in `wrangler.toml`) lets `sanitize-html` run on `workerd`. 17- **No database / KV / queues** — the read-through design needs none. Astro's default 18 session store (which would add a KV) is disabled with an in-memory driver. 19- Cloudflare's `fetch` cannot reach private/loopback IPs, which also closes the 20 DNS-rebinding residual noted in Decision 0007 — SSRF is fully contained at the edge. 21 22## Edge verification (local `workerd` via `astro preview`) 23 24- Landing (static asset) → 200. 25- Article `/@jeherve.com/<rkey>` (SSR + `sanitize-html` + reader fetch chain) → 200, renders 26 with both `site.standard` link tags. **`sanitize-html` works under `nodejs_compat`.** 27- `/@127.0.0.1/x` → 404 (SSRF guard holds on the edge). 28- Generated `dist/server/wrangler.json`: `main: entry.mjs`, `assets: ../client`, 29 `compatibility_flags: [nodejs_compat]`, `kv_namespaces: []`. 30 31## Deploy runbook (owner's Cloudflare account) 32 331. **One-time:** `npx wrangler login` (authorise the Cloudflare account). 342. **Deploy:** `npm run deploy` (= `astro build && wrangler deploy`). `astro build` writes 35 `.wrangler/deploy/config.json` redirecting `wrangler deploy` to the built worker config. 363. **Custom domain:** in the dashboard (Workers & Pages → `skypress` → Settings → Domains), 37 attach **`skypress.blog`** (the domain is already on Cloudflare). This routes the apex to 38 the Worker. 394. **Verify production:** 40 - `https://skypress.blog/` (landing), `/preview` (sample article). 41 - `https://skypress.blog/client-metadata.json` returns the OAuth client metadata 42 (`client_id` must equal that URL — it does). 43 - `https://skypress.blog/editor` → sign in (prod OAuth uses the hosted `client_id`; 44 `redirect_uris` is `https://skypress.blog/editor`), publish, then open 45 `https://skypress.blog/@<handle>/<rkey>`. 46 47Git-connected builds (Workers Builds) are an alternative: build `npm run build`, deploy 48`npx wrangler deploy`, set `nodejs_compat` — but the local `npm run deploy` is the simplest 49first cut. 50 51## OAuth client metadata: a worker route, not a static file 52 53`/client-metadata.json` is served by a **worker route** 54(`src/pages/client-metadata.json.ts`, `prerender = false`), not a static asset. Two prod 55failures drove this: 56 571. **404 in production.** The static `public/client-metadata.json` served locally and on 58 the first deploy but 404'd at the deployed origin (`invalid_client_metadata … Not 59 Found`). Static `.json` serving on Cloudflare Workers Static Assets proved unreliable; 60 a worker route always runs. 612. **Trailing slash.** Cloudflare serves the prerendered editor page canonically at 62 **`/editor/`** (`/editor` → 307 → `/editor/`), and the atproto client only processes a 63 callback when `location.pathname` **exactly** equals a registered `redirect_uri` 64 pathname (`findRedirectUrl`). So the metadata must register `…/editor/` **with** the 65 slash, or auth completes at Bluesky but the editor silently stays signed-out. 66 67The route generates the document from the **request origin**, so `client_id` always equals 68the fetched URL (apex / www / preview origins all work) and `redirect_uris` is 69`<origin>/editor/`. Verified on workerd (`astro preview`): 200 `application/json`. Reading 70routes are SSR (not slash-canonicalised), so article URLs stay `/@<handle>/<rkey>`. 71 72## Notes / follow-ups 73 74- The dev OAuth client is loopback (`127.0.0.1`); production uses the hosted 75 `client-metadata.json` automatically (Decision 0004 / `getClientMode`). 76- The editor island is heavy (~1.5 MB gz) but loads only on `/editor`; reading pages stay 77 zero-JS at the edge. 78- A caching layer / `Cache-Control` tuning for the read-through renderer is a perf 79 follow-up (content is immutable per rkey until edited).