Skip to content

Latest commit

 

History

History
133 lines (93 loc) · 7.6 KB

File metadata and controls

133 lines (93 loc) · 7.6 KB

Render Deployment

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.


TL;DR

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=/health

Render 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.

Template Repositories

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:

[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](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.

SQLite Template

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/uploads

The 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.

Postgres Template

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/uploads

The 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.

Runtime Notes

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.

Backups

Back up both data stores:

  • SQLite template: back up the Render disk mounted at /app/storage; it contains both data/cms.db and uploads/.
  • 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.

Troubleshooting

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.

Related