Skip to main content
The self-hosted image is the entire Executor server in a single container: the typed API, the MCP server, authentication, QuickJS code execution, and the web console, all in one process over a libSQL (SQLite) file. There is no external database, worker, or proxy to run.

Run it

Using the published image:
docker run -d \
  --name executor-selfhost \
  -p 4788:4788 \
  -v executor-data:/data \
  ghcr.io/rhyssullivan/executor-selfhost:latest
Or build from a clone of the repo, from apps/host-selfhost:
docker compose up -d --build
No configuration is required. Open http://localhost:4788; the first person to create an account becomes the owner. After that, people join through single-use invite links you mint from the Admin page, and open signup is closed.

Storage

Everything that must persist (the SQLite database and the generated encryption keys) lives in the data directory, mounted at /data in the container. Always mount a volume there so it survives restarts and upgrades:
-v executor-data:/data     # named volume (what compose uses)
# or a host path:
-v /srv/executor:/data
Back it up by snapshotting that volume (or copying /data, primarily data.db). EXECUTOR_DATA_DIR (default /data) sets the directory, and EXECUTOR_DB_PATH (default <data dir>/data.db) sets the database file.

Environment variables

Everything is optional: a bare run boots a working instance. The defaults below are the container defaults.
VariableDefaultPurpose
PORT4788HTTP port the server listens on.
EXECUTOR_HOST0.0.0.0Bind address. The image binds all interfaces.
EXECUTOR_DATA_DIR/dataDirectory holding the database and generated keys.
EXECUTOR_DB_PATH<data dir>/data.dbSQLite database file.
EXECUTOR_WEB_BASE_URLauto (http://localhost:4788)Public URL browsers use. Required behind a domain or TLS (see below).
BETTER_AUTH_SECRETgenerated, persisted in /dataSession secret (32+ chars). Rotating it signs everyone out.
EXECUTOR_SECRET_KEYgenerated, persisted in /dataMaster key encrypting stored secrets. Set it to manage it yourself.
EXECUTOR_BOOTSTRAP_ADMIN_EMAILunsetPre-create the admin headlessly (with the password below); skips browser first-run.
EXECUTOR_BOOTSTRAP_ADMIN_PASSWORDunsetPassword for the bootstrap admin.
EXECUTOR_BOOTSTRAP_ADMIN_NAMEAdminDisplay name for the bootstrap admin.
EXECUTOR_ORG_NAMEDefaultDisplay name of the single org every user joins.
EXECUTOR_ORG_SLUGdefaultURL slug for that org.
EXECUTOR_ALLOW_LOCAL_NETWORKfalseAllow sandboxed code to reach loopback / private addresses. Keep off unless you trust the code.

Behind a domain or TLS

Set EXECUTOR_WEB_BASE_URL to the exact public URL you load in the browser (scheme, host, and port). If it does not match, browser logins are rejected with an invalid-origin error.
docker run -d \
  -p 4788:4788 \
  -v executor-data:/data \
  -e EXECUTOR_WEB_BASE_URL=https://executor.example.com \
  ghcr.io/rhyssullivan/executor-selfhost:latest
For a headless deploy (CI or infra-as-code), set EXECUTOR_BOOTSTRAP_ADMIN_EMAIL and EXECUTOR_BOOTSTRAP_ADMIN_PASSWORD to create the admin without the browser setup screen.

Connect an agent

The server exposes a streamable-HTTP MCP endpoint at /mcp. Point your client at http://localhost:4788/mcp (or your public URL). See MCP Proxy for how that endpoint exposes your integrations.