Deployment
Docker, persistent job store, reverse proxy.
Docker
docker compose up --buildTwo credential styles in docker-compose.yml: MULERUN_TOKEN env var, or mount
~/.config/mulerun + ~/.mulerun into the container.
Persistent job store
By default jobs live in memory and are lost on restart. For production, persist:
# Local libsql file (pure-Go driver, zero deps)
CLI2API_JOBSTORE_DSN=file:/var/lib/cli2api/jobs.db ./cli2api
# Remote Turso / sqld
CLI2API_JOBSTORE_DSN="libsql://your-db.turso.io?authToken=$TURSO_TOKEN" ./cli2apiThe DSN's auth portion is automatically redacted in startup logs, so it's safe to ship them to log aggregators.
Reverse proxy (nginx)
Streaming endpoints need buffering off, or SSE and audio streams stall:
location /v1/ {
proxy_pass http://127.0.0.1:8080;
proxy_buffering off; # SSE + audio streaming
proxy_read_timeout 600s; # long polls / sync image up to 5 min
client_max_body_size 64M; # multipart image edits
}Docs site (this site)
This documentation site lives in docs/ and is a statically exported
Next.js app (output: 'export') — it builds to a plain out/ folder with no
server runtime.
Cloudflare Pages (recommended — free, global CDN):
cd docs
pnpm install && pnpm build # → ./out
npx wrangler pages deploy outOr connect the GitHub repo in the Cloudflare dashboard with root directory
docs, build command pnpm install && pnpm build, output directory out.
Locale routing on the static host is handled by public/_redirects
(/ → /en/); /en/* and /cn/* are prerendered. Search is client-side
(Orama index baked into out/api/search, mandarin tokenizer for Chinese), so
no server is involved.
Vercel / Netlify / any static host also work — point them at docs/out/.