Die serverseitige PDF-Erzeugung bedeutet oft Lambda-Cold-Starts, Chromium-Binaries oder Drittanbieter-APIs mit extra Latenz und Kosten. Wer schon einmal einen Docker-Container mit über 1 GB nur für HTML-zu-PDF gestartet hat, kennt das Problem.
Hochwertige Starter-Kits mit integriertem Authentifizierungsfluss (Auth.js), Objekt-Uploads (AWS, Clouflare R2, Firebase Storage, Supabase Storage), integrierten Zahlungen (Stripe, LemonSqueezy), E-Mail-Verifizierungsablauf (Resend, Postmark, Sendgrid) und viel mehr . Kompatibel mit jeder Datenbank (Redis, Postgres, MongoDB, SQLite, Firestore).
Get all 3 kits Bundle ↗- Next.js Starter Kit
- SvelteKit Starter Kit
- Astro Starter Kit
One-time license · Lifetime updates
Cloudflare Browser Rendering dreht dieses Modell um: ein verwalteter Headless-Chromium-Dienst auf Cloudflares Edge-Netzwerk — keine Binaries, keine Cold-Starts, keine Docker-Layer. Sie erhalten Puppeteer-kompatible APIs mit Startzeiten unter 100 ms, global verteilt.
In dieser Anleitung bauen Sie ein produktionsreifes PDF-System mit Astro, Cloudflare KV und Cloudflare Workers. Sie erstellen druckbare Belegseiten mit eigenem CSS, verdrahten einen API-Endpunkt, der Headless Chrome am Edge startet, und cachen die Ergebnisse in Cloudflare KV, um doppeltes Rendering zu vermeiden.
Voraussetzungen
Sie benötigen:
- Node.js 20 oder höher
- Ein Cloudflare-Konto
Warum Cloudflare Browser Rendering für PDFs?
- Kein Chromium-Pflegeaufwand: Cloudflare betreibt und patcht Headless Chromium für Sie.
- Edge-Nähe: PDFs nahe am Anfragenden rendern — ideal für Dashboards, Rechnungen und OG-Bilder.
- Streaming: PDFs direkt aus dem Worker senden, ohne temporäre Dateien.
- Kostenbewusst: Nutzungsbasierte Abrechnung ohne eigene Renderer-Flotte.
Architekturüberblick
1. Astro-Seite (src/pages/receipt/[id].astro) → SSR-Route mit Beleg-/Rechnungs-HTML + Print-CSS
2. PDF-API (src/pages/api/pdf/[id].ts) → Browser-Rendering-Session starten → Astro-Route-URL laden → page.pdf() aufrufen und Binary streamen
3. Cloudflare-Adapter + Browser-Binding → Astro auf Workers/Pages deployen → BROWSER-Binding für den Worker bereitstellenNeue Astro-Anwendung erstellen
Starten Sie mit einem neuen Astro-Projekt. Führen Sie aus:
npm create astro@latest my-astro-kv-pdf-appcd my-astro-kv-pdf-appnpm install wrangler @cloudflare/puppeteerWählen Sie bei den Prompts:
Use minimal (empty) template, wenn gefragt wird, wie das Projekt starten soll.Yes, wenn Abhängigkeiten installiert werden sollen.Yes, wenn ein Git-Repository initialisiert werden soll.
Danach ins Projektverzeichnis wechseln und die App starten:
npm run devDie App läuft unter localhost:4321.
Cloudflare-Adapter in Ihr Astro-Projekt integrieren
Für Cloudflare Workers und Cloudflare KV installieren Sie den Cloudflare-Adapter:
npx astro add cloudflare --yesSetzen Sie in astro.config.mjs output auf server:
import { defineConfig } from 'astro/config';import cloudflare from '@astrojs/cloudflare';
export default defineConfig({ output: 'server', adapter: cloudflare()});Browser Rendering in wrangler.jsonc konfigurieren
Fügen Sie ein BROWSER-Binding hinzu, damit der Worker Headless Chromium starten kann:
{ "main": "dist/_worker.js/index.js", "name": "my-astro-kv-pdf-app", "compatibility_date": "2025-12-06", "compatibility_flags": [ "nodejs_compat", "global_fetch_strictly_public" ], "assets": { "binding": "ASSETS", "directory": "./dist" }, "observability": { "enabled": true }, "browser": { "binding": "BROWSER" }}Der Block
browserstellt Cloudflares Browser-Rendering-Dienst bereit und macht ihn alsenv.BROWSERim Worker verfügbar.
KV für Caching hinzufügen
Erstellen Sie einen KV-Namespace für generierte PDFs:
npx wrangler kv namespace create PDF_CACHEDie Ausgabe enthält eine id für wrangler.jsonc. Ergänzen Sie das KV-Binding:
{ "main": "dist/_worker.js/index.js", "name": "my-astro-kv-pdf-app", "compatibility_date": "2025-12-06", "compatibility_flags": [ "nodejs_compat", "global_fetch_strictly_public" ], "assets": { "binding": "ASSETS", "directory": "./dist" }, "observability": { "enabled": true }, "browser": { "binding": "BROWSER" }, "kv_namespaces": [ { "binding": "PDF_CACHE", "id": "generated-id", "remote": true } ]}TypeScript-Typen hinzufügen
Erstellen Sie src/env.d.ts für die Cloudflare-Bindings:
/// <reference types="astro/client" />
type KVNamespace = import('@cloudflare/workers-types').KVNamespace
type ENV = { PDF_CACHE: KVNamespace BROWSER: Fetcher}
type Runtime = import('@astrojs/cloudflare').Runtime<ENV>
declare namespace App { interface Locals extends Runtime {}}Damit sind locals.runtime.env.PDF_CACHE und locals.runtime.env.BROWSER in Ihren Routen typisiert.
Druckbare Astro-Seite erstellen
Belegseite mit druckfreundlichen Styles:
---const { id } = Astro.params;const order = { id, customer: 'Ada Lovelace', total: '$128.00', items: [ { name: 'Edge Functions', price: '$50.00' }, { name: 'PDF Rendering', price: '$78.00' } ]};---
<html lang="en"> <head> <meta charset="UTF-8" /> <title>Receipt #{order.id}</title> <style> :root { font-family: 'Inter', system-ui, -apple-system, sans-serif; } body { margin: 0; padding: 32px; color: #0f172a; } header { display: flex; align-items: center; justify-content: space-between; } table { width: 100%; border-collapse: collapse; margin-top: 24px; } th, td { padding: 12px 8px; text-align: left; border-bottom: 1px solid #e2e8f0; } .total { text-align: right; font-size: 1.125rem; font-weight: 700; } @page { margin: 24mm; } @media print { body { background: white; } a[href]::after { content: ''; } } </style> </head> <body> <header> <div> <h1>Receipt #{order.id}</h1> <p>Issued to {order.customer}</p> </div> <strong>launchfa.st</strong> </header> <table> <thead> <tr><th>Item</th><th>Price</th></tr> </thead> <tbody> {order.items.map(item => ( <tr> <td>{item.name}</td> <td>{item.price}</td> </tr> ))} </tbody> </table> <p class="total">Total: {order.total}</p> </body></html>Speichern als src/pages/receipt/[id].astro. Das Print-CSS (@page) setzt Ränder; @media print entfernt störende Link-Dekorationen.
PDF-API-Route erstellen
Worker-API-Route mit Cloudflare Browser Rendering: PDF aus der Astro-HTML-Belegseite erzeugen und cachen.
Unter src/pages/api/pdf/[id].ts:
- prüfen, ob ein PDF in Cloudflare KV liegt, und es sofort zurückgeben
- bei Cache-Miss Headless-Browser über Browser Rendering starten
- zur druckbaren Seite navigieren und PDF erzeugen
- PDF sieben Tage in KV speichern
import type { APIRoute } from "astro";import puppeteer from "@cloudflare/puppeteer";
// Helper to create a proper PDF HTTP responseconst pdfResponse = (pdf: Buffer<ArrayBuffer>, id: string) => { return new Response(pdf, { headers: { 'Content-Type': 'application/pdf', 'CDN-Cache-Control': 'max-age=604800', 'Content-Disposition': `inline; filename="receipt-${id}.pdf"` } });}
export const GET: APIRoute = async ({ locals, params, request }) => { const id = params.id as string; const origin = new URL(request.url).origin; const targetUrl = `${origin}/receipt/${id}`; const cache = locals.runtime.env.PDF_CACHE;
// Try KV cache first to avoid unnecessary browser work const cachedPdf = await cache.get(targetUrl, "arrayBuffer"); if (cachedPdf) return pdfResponse(Buffer.from(cachedPdf), id);
// Only run browser in Cloudflare's env if (!locals.runtime.env.BROWSER) return new Response('Browser binding not available locally', { status: 501 });
// Launch browser and render HTML to PDF const session = await puppeteer.launch(locals.runtime.env.BROWSER); const page = await session.newPage(); await page.goto(targetUrl, { waitUntil: 'networkidle0' }); const pdf = await page.pdf({ format: 'A4', printBackground: true, margin: { top: '24mm', right: '18mm', bottom: '24mm', left: '18mm' } }); await session.close();
const result = Buffer.from(pdf); // Cache for a week (604800 seconds) await cache.put(targetUrl, result, { expirationTtl: 60 * 60 * 24 * 7 }); return pdfResponse(result, id);};Unter /api/pdf/123 erhalten Sie ein live aus /receipt/123 erzeugtes PDF. Folgeanfragen liefern das gecachte PDF bis zum Ablauf.
PDFs schützen und cachen
- Auth: Vor dem Rendern Session-Token oder signierte Query-Strings verlangen. Unauthentifizierte Anfragen früh ablehnen.
- Caching: Statische Rechnungen kurz cachen (
Cache-Control: public, max-age=300). Dynamische Inhalte privat halten. - Rate Limits: Bei hohem Traffic einen Rate Limiter (KV) ergänzen.
Auf Cloudflare Workers deployen
# Build the projectnpm run build
# Deploy to Cloudflare Workersnpx wrangler deployNach dem Deploy ist die API unter https://your-worker.workers.dev/api/pdf/[id] erreichbar.
Fazit
Cloudflare Browser Rendering macht PDF-Erzeugung zu einer leichten Edge-Funktion. Astro SSR plus Headless Chromium am Edge liefert Rechnungen, Belege und Reports on-demand — ohne Infrastruktur und ohne Cold-Starts.
Für fortgeschrittene Fälle: Mehrseitige Dokumente, eigene Kopf-/Fußzeilen oder Screenshots für Open-Graph-Bilder. Die Browser-Rendering-API bietet volle Puppeteer-Kontrolle am Cloudflare-Edge.
Fragen oder Anmerkungen? Schreiben Sie mir auf Twitter.