Instatic Deployment Options: Docker, VPS, Render, and Railway Guide
Instatic supports four primary deployment methods: self-hosted Docker VPS using Compose, managed Render hosting, managed Railway hosting, and generic Docker image deployment on any container-compatible infrastructure.
Instatic is a Bun-powered content management system developed by CoreBunch that ships with production-ready containerization. While the application can run on any platform capable of executing a Bun process, the project provides comprehensive Docker-based recipes optimized for VPS, Render, and Railway environments. All deployment configurations rely on the centralized server/config.ts module to manage runtime environment variables.
Docker VPS Deployment
The self-hosted VPS option provides maximum flexibility through Docker Compose override files. The base configuration resides in docker-compose.yml and compose.prod.yml, which define the core application service, networking, and environment defaults.
SQLite with Docker Compose
For single-server deployments with moderate traffic, combine the production base with the SQLite override and optional TLS:
docker compose \
-f compose.prod.yml \
-f compose.sqlite.yml \
-f compose.tls.yml \
-f compose.build.yml \
up -d --build
This stack creates an app container running the Bun server with DATABASE_URL set to sqlite:/app/data/cms.db. Data persists in named Docker volumes for both the database (data) and uploaded media (uploads). The compose.tls.yml file injects a Caddy container that handles TLS termination and forwards traffic to the application, while compose.build.yml forces a local image rebuild from source.
Postgres with TLS
For production workloads requiring concurrent connections, use the Postgres service instead of SQLite:
docker compose \
-f compose.prod.yml \
-f compose.tls.yml \
-f compose.build.yml \
up -d --build
This configuration launches three containers: app, postgres, and caddy. The application receives a DATABASE_URL pointing to the bundled Postgres instance. Detailed configuration options are documented in docs/deployment/vps.md.
Render Deployment
Render hosts Instatic using the pre-built container image ghcr.io/corebunch/instatic. The platform pulls the image defined in the Dockerfile and exposes the application on port 3001.
A typical Render Blueprint configuration appears as follows:
services:
- name: web
type: web
env: docker
dockerfile: Dockerfile
docker_context: .
ports:
- 10000:3001
env_vars:
INSTATIC_SECRET_KEY: ${INSTATIC_SECRET_KEY}
PUBLIC_ORIGIN: https://cms.example.com
health_check:
path: /health
interval: 10s
disks:
- name: uploads
mount_path: /app/uploads
size_gb: 5
Render requires a persistent disk mounted at /app/uploads for media storage and provisions managed Postgres instances that automatically inject DATABASE_URL into the container environment. The health check endpoint at /health ensures zero-downtime deployments.
Railway Deployment
Railway operates similarly to Render, pulling the ghcr.io/corebunch/instatic image and exposing the service on a public HTTP port. As detailed in docs/deployment/railway.md, Railway's "Image Auto Updates" feature keeps the deployment current without manual intervention.
A simplified Railway service definition:
[service]
name = "instatic"
image = "ghcr.io/corebunch/instatic:latest"
port = 10000
[service.env]
INSTATIC_SECRET_KEY = "REPLACE_WITH_GENERATED_KEY"
PUBLIC_ORIGIN = "https://my-cms.onrender.com"
[[service.volumes]]
path = "/app/uploads"
size = "5Gi"
Railway automatically configures health checks and enables persistent volume mounting for uploads. Managed Postgres databases can be attached via the Railway dashboard, which injects the connection string into the container's environment.
Generic Docker Image Deployment
Any infrastructure capable of running Linux containers can host Instatic using the production image directly. The Dockerfile defines a multi-stage build that embeds the compiled admin SPA (dist/) and retains esbuild in production dependencies for runtime bundling.
For custom orchestration or Kubernetes environments:
docker run -d \
-p 3001:3001 \
-e INSTATIC_SECRET_KEY=<key> \
-e DATABASE_URL=sqlite:/app/data/cms.db \
-v instatic-uploads:/app/uploads \
ghcr.io/corebunch/instatic:latest
This approach bypasses Compose entirely while maintaining persistent storage through Docker volumes. The image contract and additional examples are documented in docs/deployment/docker-image.md.
Direct Bun Execution
For development environments or minimal installations where Docker is unavailable, Instatic can run directly on the host Bun runtime:
bun install
bun run build
INSTATIC_SECRET_KEY=$(bun run scripts/generate-secret-key.ts) \
DATABASE_URL=sqlite:./data/cms.db \
STATIC_DIR=./dist \
UPLOADS_DIR=./uploads \
PORT=3001 \
bun run server/index.ts
This method requires manual environment configuration and places the burden of process management, TLS termination, and database administration on the operator.
Configuration Management
All deployment methods rely on server/config.ts to normalize runtime settings. Critical environment variables include:
PORT: HTTP server port (default 3001)DATABASE_URL: Connection string for SQLite or PostgresUPLOADS_DIR: Filesystem path for media storage (typically/app/uploads)STATIC_DIR: Location of compiled frontend assetsPUBLIC_ORIGIN: Canonical URL for the instanceTRUSTED_PROXY_CIDRS: IP ranges for reverse proxy trustINSTATIC_SECRET_KEY: Cryptographic key for session signing
These variables are defined in the various .env examples and injected by the respective deployment platforms' configuration files.
Summary
- Docker VPS offers self-hosted flexibility with SQLite or Postgres backends, optional Caddy TLS termination via
compose.tls.yml, and persistent named volumes. - Render provides managed hosting via Blueprint configuration, persistent disks, and integrated health checks using the pre-built
ghcr.io/corebunch/instaticimage. - Railway delivers similar managed hosting with automatic image updates, volume persistence at
/app/uploads, and managed database provisioning. - Generic Docker enables deployment on any container-compatible infrastructure using standard
docker runcommands or Kubernetes manifests referencing the published image.
Frequently Asked Questions
Can I run Instatic without Docker?
Yes, though it requires manual environment configuration. You can execute bun run server/index.ts directly after running bun install and bun run build, setting INSTATIC_SECRET_KEY, DATABASE_URL, and other required variables manually. This approach is suitable for development or minimal installations but lacks the production hardening provided by the containerized deployment recipes.
Which database should I use for production VPS deployments?
Use Postgres via compose.prod.yml without the SQLite override for production environments requiring high concurrency or multiple simultaneous connections. Use SQLite via compose.sqlite.yml for single-server deployments with lower traffic volumes, as it simplifies backup and reduces resource overhead according to docs/deployment/vps.md.
How does TLS certificate management work in VPS deployments?
The compose.tls.yml file injects a Caddy reverse proxy container that automatically provisions and renews Let's Encrypt certificates. Caddy terminates TLS and forwards unencrypted traffic to the Instatic application container on the internal Docker network, requiring no manual certificate management.
What are the minimum server requirements for VPS deployment?
Instatic requires a Linux server capable of running Docker Engine 20.10 or later with support for Compose V2. The Bun runtime consumes approximately 100-200MB RAM plus database overhead. SQLite deployments require minimal disk I/O, while Postgres deployments benefit from SSD storage for database volumes mounted via Docker named volumes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →