Use the production Compose stack for a single-node installation. It starts the app, realtime, PostgreSQL with pgvector, Redis, migrations, and the scheduler.
Prerequisites
- Docker Engine or Docker Desktop, running.
- Docker Compose 2.24.0 or later. The file uses optional
env_fileentries introduced in that version. - Bun for
bunx, and Node.js 20 or later for the publishedsim-setupexecutable. - Available host ports 3000 and 3002, with enough resources for your workload. See resource examples.
- A public domain and TLS proxy for remote access.
Quick start
The wizard creates ./sim with a generated .env and production Compose file, then starts published container images. Pass --dir <path> for another directory. Open http://localhost:3000.
For a manual installation, obtain the Compose file from a source checkout:
Then follow the configuration steps below.
Production setup
1. Configure the environment
For a new installation, create .env next to docker-compose.prod.yml:
If you already ran the wizard or have an existing installation, edit that .env and retain its keys and database credentials. Do not rerun this creation command over it.
Compose derives BETTER_AUTH_URL from NEXT_PUBLIC_APP_URL and DATABASE_URL from POSTGRES_*. Setting either derived variable in .env does not override the service definition. To use an external database, maintain a Compose configuration that supplies the same external DSN to the app, realtime, and migrations and adjusts their bundled-database dependencies.
Keep POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB URL-safe: letters, digits, ., _, ~, or -. Compose inserts them into the DSN without escaping; values containing @, /, ?, #, %, or spaces can initialize PostgreSQL but prevent app connections. Hex output from openssl is safe.
Compose refuses startup without BETTER_AUTH_SECRET, ENCRYPTION_KEY, INTERNAL_API_SECRET, or POSTGRES_PASSWORD. PostgreSQL applies its credentials only when initializing a new volume; changing .env does not change an existing database password. See Postgres on Compose before rotating it.
Set CRON_SECRET for scheduled work. Without it, the cron service prints instructions and exits; the other services can still run. Images use latest unless you set SIM_VERSION; the separate scheduler image uses SIM_CRON_VERSION. Pin and upgrade deliberately using Upgrades.
2. Configure durable uploads
Follow Object storage for AWS S3, Azure Blob, Google Cloud Storage, or local-volume configuration. Local disk is not shared across app replicas.
3. Start and verify services
Expect five services running and migrations exited successfully. The migrator has no healthcheck because it is a one-shot job.
Confirm the scheduler calls succeed, then run Verify your install.
4. Serve the public origin over TLS
A host-installed Caddy proxy can obtain and renew certificates for your domain. For example:
Route /socket.io to realtime on 3002 and other requests to the app on 3000. The 250 MB decimal Caddy limit clears the configured 220 MiB deployed-chat cap, but the app's current Next.js proxy buffer still limits matching requests to 10 MiB. See Request size limits before increasing payload sizes. flush_interval -1 explicitly disables response buffering; Caddy already flushes SSE immediately. It also keeps the upstream request running if the client disconnects. See Caddy streaming behavior.
This example assumes Caddy runs on the Docker host. A containerized proxy needs reachable Compose service addresses instead of its own localhost. For Nginx, Traefik, cloud load balancers, or separate socket hosts, see Networking.
Ollama
External Ollama
For production, keep this Compose stack and point OLLAMA_URL at an Ollama server. If it runs on the Docker host, save the address in .env so later recreations retain it:
Production Compose maps host.docker.internal to the host gateway, including on Linux. You can instead use a reachable host IP. The Ollama server must listen on an interface reachable from the container.
Development Ollama stack
docker-compose.ollama.yml builds the app, realtime, and migrations from source. It does not bundle Redis or cron. Without Redis, pub/sub is process-local and CLI pairing approval has no fallback; idempotency and execution-progress storage can fall back to PostgreSQL. Without a scheduler, background jobs do not run.
Use a server profile together with setup; setup alone starts no Ollama server and the model setup waits:
Setup pulls gemma3:4b. To pull another model:
LM Studio
Start LM Studio's local server, load a model, enable Serve on Local Network, and configure API authentication. Save these values beside your Compose file:
Use a reachable host IP when needed. Sim accepts the server root or a /v1 URL. Models appear with a vllm/ prefix, which Sim removes before sending the model ID to LM Studio.
Recreate the app using the file that started your installation:
The sim-setup CLI
Invoke commands as bunx sim-setup <command> unless the package is installed globally. Run doctor, config, and the wizard from the configuration directory. Lifecycle commands discover running production/local Compose stacks, source checkouts, and Helm releases; Ollama-stack installs are not managed.
--dir <path> works with every command and scopes standalone lifecycle commands to that installation.
For Compose, reset archives .env beside the Compose file. For dev, Kubernetes, or no detected install, it archives apps/sim/.env, apps/realtime/.env, packages/db/.env, and root .env. Preserve any backups before intentionally removing volumes.
add writes beside the Compose file or to apps/sim/.env on a source checkout. Recreate containers that read the change: cache changes REDIS_URL for both app and realtime. For a source checkout, mirror shared values into apps/realtime/.env. restart alone does not apply changed container environment. Desktop discovery refuses configurations naming different origins; pass --url to choose.
Back up and update
For the default database role/name:
Restore only to the intended database:
Use your configured role/database if you changed POSTGRES_*. -T disables TTY allocation for redirected input/output. Compose stores database data in the postgres_data volume; file uploads and encryption keys need separate backups.
For an image update, change the pinned SIM_VERSION in .env, then:
Read Upgrades before updating or restoring an existing installation.