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.
| Service | Container / Runtime | Port | Health |
|---|---|---|---|
| Frontend | Next.js | 3010 | — |
| Backend | Express or Hono | 5010 | GET /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 recommended path: Studio
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
| Variable | Purpose |
|---|---|
BETTER_AUTH_SECRET | Session signing secret — generate with openssl rand -base64 32 |
DATABASE_URL | Database connection string |
FRONTEND_ORIGIN | Frontend URL, for CORS (single-frontend mode) |
AUTH_ALLOWED_HOSTS | Comma-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_DOMAIN | Parent 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_URL | Public 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
| Variable | Purpose |
|---|---|
NEXT_PUBLIC_API_BASE_URL | Public URL of the backend API |
Production checklist
- Set
BETTER_AUTH_SECRET - Set
DATABASE_URL - Set
FRONTEND_ORIGINandBACKEND_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/healthresponds
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
OriginagainstAUTH_ALLOWED_HOSTS(bothhttps://andhttp://variants, with wildcard pattern matching). WhenAUTH_ALLOWED_HOSTSis unset, it falls back to single-originFRONTEND_ORIGIN. - Auth (
@siteknock/auth): Better Auth uses dynamic base URL resolution — per-request fromx-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
Containers & Compose
Build and run the two services.
Hosted PaaS Deploys
Deploy to Vercel, Cloudflare Workers, Railway, or Netlify.
Convex Backend Deploys
Deploy a serverless Convex backend from Studio.
Backend Frameworks
Express vs Hono and how to switch.
Migrations & Health
Apply migrations safely and verify health.