Skip to content

Hosting and scaling

One web process, one worker, and PostgreSQL run a site comfortably. When traffic grows:

  1. Put a CDN in front. Public pages are sent with headers that let a CDN keep them for 5 minutes and serve a slightly old copy while it refreshes. With CDN_PROVIDER=cloudflare or fastly and its credentials, sc-cms clears exactly the affected pages from the CDN whenever content, menus, design, themes, or plugins change. The admin, previews, and private content are never cached.
  2. Add web servers. They share nothing but the database and storage, so any server can answer any request. Switch to STORAGE_DRIVER=s3 first, set TRUSTED_PROXY_HOPS, and size PostgreSQL’s connection limit for the number of servers (each keeps up to 10 connections).
  3. Add workers if background work falls behind. Each job runs once, however many workers there are.

pnpm load-test --url https://staging.example.com measures speed and error rates against a staging site. Details: scaling guide (in the code repository).

sc-cms can run on Cloudflare: Containers for web and worker, R2 for media and backups, and a managed PostgreSQL 18 in the same region, connected directly over TLS. Cloudflare’s D1 database and Hyperdrive can’t be used: sc-cms needs PostgreSQL features neither provides.

The Cloudflare guide walks through every step: buckets, the small routing Worker, secrets, deploying, staging, and a launch checklist.

  • Health: /api/v1/health answers when the site and database are up.
  • Logs are JSON lines on standard output.
  • Metrics: set METRICS_TOKEN and scrape /-/metrics with Prometheus.
  • Traces: set the standard OpenTelemetry variables (OTEL_EXPORTER_OTLP_ENDPOINT).

Details: observability guide (in the code repository).