DeploymentDeployment Overview

Deployment Overview

How SiteKnock apps deploy — two independent services, external services, and the environment variables you need to set.

The deployment model

A SiteKnock app deploys as two independent services: a Next.js frontend and a backend. The backend framework can be Express (the default, container-only) or Hono (runs on Node.js and edge runtimes). Separating the two services lets you scale, restart, and roll out each tier on its own.

ServiceContainer / RuntimePortHealth
FrontendNext.js3010
BackendExpress or Hono5010GET /api/health

The backend framework is set per app in config/sk-config.jsonc via the backendFramework field ("express" or "hono"). Hono backends can deploy to edge platforms (Cloudflare Workers, Vercel Functions, Netlify Functions) in addition to containers. See Backend Frameworks for the full comparison and how to switch.

External services

In production you connect your app to managed or self-hosted services:

  • Database — PostgreSQL (recommended), MySQL/MariaDB, SQLite, or SQL Server.
  • Storage — S3-compatible (AWS S3, Cloudflare R2, MinIO) or filesystem.
  • Email — SMTP, Resend, Mailgun, or SES.
  • Stripe — when billing is enabled.
  • Redis — for shared cache and rate limiting across multiple replicas.

The simplest way to deploy is Studio's deploy flow, which builds your containers, applies migrations, starts services with your configured environment, and runs health checks.

Environment variables

Backend

VariablePurpose
BETTER_AUTH_SECRETSession signing secret — generate with openssl rand -base64 32
DATABASE_URLDatabase connection string
FRONTEND_ORIGINFrontend URL, for CORS (single-frontend mode)
AUTH_ALLOWED_HOSTSComma-separated list of allowed frontend hostnames for CORS and auth — supports wildcards like *.siteknock.com. Set this when one backend serves multiple frontends. See Multi-frontend auth.
AUTH_COOKIE_DOMAINParent domain for the session cookie (e.g. .siteknock.com) so it's shared across subdomains. Required when using AUTH_ALLOWED_HOSTS with multiple subdomain frontends.
BACKEND_PUBLIC_URLPublic URL of the backend
STORAGE_*Storage provider credentials (for S3)
EMAIL_*Email provider credentials
STRIPE_*Stripe keys and webhook secret (if billing is enabled)

Frontend

VariablePurpose
NEXT_PUBLIC_API_BASE_URLPublic URL of the backend API

Production checklist

  • Set BETTER_AUTH_SECRET
  • Set DATABASE_URL
  • Set FRONTEND_ORIGIN and BACKEND_PUBLIC_URL
  • Configure Stripe keys and webhook secret (if billing)
  • Configure your email provider and credentials
  • Set NEXT_PUBLIC_API_BASE_URL
  • Configure your storage provider and credentials
  • Apply database migrations
  • Verify GET /api/health responds

Multi-frontend auth and CORS

By default, the backend allows CORS and auth from a single frontend origin set via FRONTEND_ORIGIN. This is the common case — one frontend, one backend.

When a single backend serves multiple frontends (for example, the same backend powering deployments on different cloud platforms like Railway, Vercel, Netlify, and Cloudflare), set AUTH_ALLOWED_HOSTS instead. This is a comma-separated list of hostnames (no protocol) that the backend allows for both CORS and Better Auth's dynamic base URL resolution. Each entry can be an explicit hostname or a wildcard pattern, and you can mix both in the same list:

# Wildcard — allow any *.siteknock.com subdomain
AUTH_ALLOWED_HOSTS=*.siteknock.com

# Explicit — list each frontend hostname
AUTH_ALLOWED_HOSTS=demo-railway.siteknock.com,demo-vercel.siteknock.com,demo-netlify.siteknock.com

# Mixed — wildcard for one domain, explicit for others
AUTH_ALLOWED_HOSTS=*.siteknock.com,app.example.com

Wildcard semantics match Better Auth's wildcardMatch: * crosses dots but not slashes. So *.siteknock.com matches demo.siteknock.com and a.b.siteknock.com (multi-level subdomains), but not evil.siteknock.com.attacker.com (doesn't end with .siteknock.com) and not the apex siteknock.com (no subdomain label). This keeps wildcard origins safe while supporting nested subdomains.

When using AUTH_ALLOWED_HOSTS with subdomain frontends, also set AUTH_COOKIE_DOMAIN to the parent domain so the session cookie is shared across all frontends:

AUTH_COOKIE_DOMAIN=.siteknock.com

How it works

  • CORS (generated server): the CORS middleware validates the request Origin against AUTH_ALLOWED_HOSTS (both https:// and http:// variants, with wildcard pattern matching). When AUTH_ALLOWED_HOSTS is unset, it falls back to single-origin FRONTEND_ORIGIN.
  • Auth (@siteknock/auth): Better Auth uses dynamic base URL resolution — per-request from x-forwarded-host — so OAuth redirects, email links, and session cookies point to the correct frontend. Wildcard patterns are passed through to Better Auth as-is.

Adding a new PaaS frontend

If you're using a wildcard like *.siteknock.com, no config change is needed — any new subdomain is already allowed. Otherwise, add the new frontend hostname to AUTH_ALLOWED_HOSTS in the backend's deployment environment env vars and redeploy the backend.

Hosted PaaS alternatives

If you don't want to build and run Docker containers, Studio can deploy directly to hosted platforms — Vercel, Cloudflare Workers, Railway, Netlify, and Convex. Each is a Hosted PaaS target: the platform runs your code, Studio handles credentials, resource provisioning, and the deploy command. Vercel, Cloudflare Workers, and Netlify can host both the frontend and a Hono backend; Express backends are container-only. See Hosted PaaS Deploys for the overview, or Convex Backend Deploys for the serverless backend guide.

Next steps