This guide defines the Render Blueprint configuration for Instatic.
Render can run Instatic from the published Docker image, provide a public web service, attach a persistent disk, provision managed Postgres, and generate stable secret values at deploy time. The checked-in Blueprint templates live under docs/deployment/render/ and are intended to be copied as the root render.yaml in dedicated Deploy to Render template repositories.
| Template | Blueprint | Database | Persistent storage |
|---|---|---|---|
| SQLite | docs/deployment/render/sqlite/render.yaml |
SQLite file | One Render disk mounted at /app/storage |
| Postgres | docs/deployment/render/postgres/render.yaml |
Render Postgres | One Render disk for uploads and published artefacts |
Both templates use:
Image=ghcr.io/corebunch/instatic:latest
PORT=10000
UPLOADS_DIR=/app/storage/uploads
STATIC_DIR=/app/dist
INSTATIC_SECRET_KEY=<generated by Render>
Health check path=/healthRender auto-injects RENDER_EXTERNAL_URL (the full public URL) into every web service at runtime. Instatic uses it as the CSRF public origin, so no proxy or origin variable needs to be set for a one-click deploy.
Use SQLite for the default one-click install. Use Postgres when the operator wants managed database backups, several simultaneous admin writers, or a path to more app instances after the app storage layer moves off local disk.
Render's one-click flow reads a Blueprint from a Git repository. For public install buttons, keep tiny template repositories whose root render.yaml is copied from this repo:
| Template repo | Source file |
|---|---|
corebunch/instatic-render-sqlite |
docs/deployment/render/sqlite/render.yaml |
corebunch/instatic-render-postgres |
docs/deployment/render/postgres/render.yaml |
Each template repo README can expose a button:
[](https://render.com/deploy?repo=https://github.com/corebunch/instatic-render-sqlite)Use runtime: image in the Blueprint so Render pulls the published image instead of building from the public source repository during every user install. The checked-in template uses latest so new Deploy to Render installs start from the current stable image. Release bundles rewrite the copied Blueprint files to the bundle's semver tag.
docs/deployment/render/sqlite/render.yaml provisions one web service and one persistent disk:
Service: instatic
Image: ghcr.io/corebunch/instatic:latest
Disk: /app/storage
DATABASE_URL=sqlite:/app/storage/data/cms.db
UPLOADS_DIR=/app/storage/uploadsThe SQLite adapter creates the parent directory for /app/storage/data/cms.db on boot. The same disk stores uploaded media, fonts, plugin packages, and published disk artefacts under /app/storage/uploads.
Render persistent disks are paid-service features and are attached to one service instance. The template sets plan: starter and numInstances: 1.
docs/deployment/render/postgres/render.yaml provisions one web service, one persistent disk, and one Render Postgres instance:
Service: instatic
Image: ghcr.io/corebunch/instatic:latest
Disk: /app/storage
Database: instatic-db
DATABASE_URL=<Render internal Postgres connection string>
UPLOADS_DIR=/app/storage/uploadsThe database uses:
plan=basic-256mb
diskSizeGB=15
databaseName=instatic
user=instatic
ipAllowList=[]ipAllowList: [] keeps the database reachable only from Render's private network. The app still needs the persistent disk because Postgres stores content rows, but uploaded files, fonts, plugin packs, and published artefacts live under UPLOADS_DIR.
Render web services use PORT=10000 by default. The templates set PORT explicitly because the Docker image's default is 3001.
Render terminates HTTPS at its public web service layer before forwarding traffic to the container, so the container sees plain HTTP. Instatic derives its CSRF public origin from the RENDER_EXTERNAL_URL value Render auto-injects, so no proxy trust or origin variable is required. To front the app with a custom domain, set PUBLIC_ORIGIN to a comma-separated list that includes both the Render URL and your custom origin, e.g. PUBLIC_ORIGIN=https://app.onrender.com,https://www.example.com.
TRUSTED_PROXY_CIDRS is not used for CSRF and is omitted from the templates. It is an optional knob for client-IP attribution only (audit logs, rate-limit keys): set it to Render's ingress proxy CIDR if you want real client IPs in audit logs, and trust only your actual proxy CIDRs — never 0.0.0.0/0 for a public-facing service.
INSTATIC_SECRET_KEY uses Render's generateValue: true support. Operators should copy the generated value from Render's environment settings into their password manager after first deploy. Losing the value means stored AI provider credentials and plugin secret settings must be re-entered and TOTP MFA must be re-enrolled.
Do not add a separate migration command. server/index.ts creates the DB client from DATABASE_URL and runs the matching migrations before the HTTP server starts.
Back up both data stores:
- SQLite template: back up the Render disk mounted at
/app/storage; it contains bothdata/cms.dbanduploads/. - Postgres template: back up the Render Postgres database and the Render disk mounted at
/app/storage; the disk contains uploaded media, fonts, plugin packages, and published artefacts.
Render disk snapshots cover the app disk. Render Postgres backups cover the managed database according to the selected database plan.
| Symptom | Check |
|---|---|
| Deploy health check fails | Health check path must be /health; the app must listen on PORT=10000. |
| Public URL returns a service error | Confirm the PORT environment variable is 10000. |
| SQLite data disappears after redeploy | DATABASE_URL must point under the mounted disk, e.g. sqlite:/app/storage/data/cms.db. |
| Uploaded files disappear after redeploy | UPLOADS_DIR must point under the mounted disk, e.g. /app/storage/uploads. |
First-run setup or login returns Forbidden: invalid origin |
Render auto-injects RENDER_EXTERNAL_URL; confirm you are opening that exact URL. If you front the app with a custom domain, append it to PUBLIC_ORIGIN (comma-separated alongside the Render URL). |
| Postgres app cannot connect | DATABASE_URL must use fromDatabase with property: connectionString. |
| Adding an AI provider credential or enabling TOTP MFA returns 500 | Confirm INSTATIC_SECRET_KEY exists and has not been rotated. |
| The service deploys from source instead of the release image | The Blueprint should use runtime: image, not runtime: docker. |
- deployment/README.md — deployment overview
- docker-image.md — generic Docker image contract
- backup-restore.md — backup rules
docs/deployment/render/sqlite/render.yaml— SQLite Render Blueprintdocs/deployment/render/postgres/render.yaml— Postgres Render Blueprintserver/config.ts— runtime env parsingserver/db/index.ts— database URL detectionDockerfile— production image- Render docs: Blueprint spec, Deploy to Render button, web services, environment variables, persistent disks, prebuilt Docker images