---
title: "Self-host Executor, the open-source MCP gateway"
description: "Run Executor 2 on an exe.dev VM: add MCP servers and APIs once, keep their credentials on your server, and point Claude Code, Codex and Shelley at one private MCP URL."
url: https://exe.dev/deploy/executor
category: "AI agents"
updated: 2026-10-31
---

# Self-host Executor, the open-source MCP gateway

Add your tools once; every agent reaches them through one private MCP URL.

- **Software:** Executor (https://executor.sh)
- **Source:** https://github.com/UsefulSoftwareCo/executor
- **License:** MIT
- **Time:** 10 minutes
- **Example VM name:** `my-executor` (yours will differ; on the VM, `hostname` prints it)
- **Machine-readable:** https://exe.dev/deploy/executor/manifest.json

## What you get

- Executor 2 at `https://my-executor.exe.xyz`, in Docker, restarted on failure and after a reboot.
- Its database, generated keys and your apps' code in `~/executor/data`.
- An owner account that only you can create, because the setup page is behind your exe.dev login.
- One MCP endpoint, `/mcp`, that Claude Code, Codex, Shelley and other agents share.
- A backup and update procedure for the data directory.

Running on the VM:

- **Executor 2 (beta)**: ghcr.io/usefulsoftwareco/executor-selfhost:2.0.0-beta.34 in Docker Compose: dashboard, MCP endpoint and app runtime, port 8000, data in `~/executor/data`

How it is reached:

- https://my-executor.exe.xyz/ (private): the dashboard, behind your exe.dev login and your Executor account
- https://my-executor.exe.xyz/mcp (private): the MCP endpoint; agents send an exe.dev VM token and an Executor token

## Deploy with Shelley

Open https://exe.dev/new?prompt=Set%20up%20Executor%20on%20this%20VM%20by%20following%20the%20exe.dev%20recipe%20at%20https%3A%2F%2Fexe.dev%2Fdeploy%2Fexecutor.md%20from%20top%20to%20bottom.%0A%0AThe%20recipe%27s%20example%20VM%20name%20is%20my-executor.%20This%20VM%27s%20name%20is%20the%20output%20of%20%60hostname%60%3A%20use%20it%20wherever%20the%20recipe%20writes%20my-executor.%20Skip%20the%20step%20that%20creates%20the%20VM%3B%20you%20are%20on%20it.%0A%0AYou%20are%20done%20when%20all%20of%20these%20are%20true.%20Check%20each%20one%20yourself%3A%0A-%20Executor%202%20at%20%60https%3A%2F%2Fmy-executor.exe.xyz%60%2C%20in%20Docker%2C%20restarted%20on%20failure%20and%20after%20a%20reboot.%0A-%20Its%20database%2C%20generated%20keys%20and%20your%20apps%27%20code%20in%20%60~%2Fexecutor%2Fdata%60.%0A-%20An%20owner%20account%20that%20only%20you%20can%20create%2C%20because%20the%20setup%20page%20is%20behind%20your%20exe.dev%20login.%0A-%20One%20MCP%20endpoint%2C%20%60%2Fmcp%60%2C%20that%20Claude%20Code%2C%20Codex%2C%20Shelley%20and%20other%20agents%20share.%0A-%20A%20backup%20and%20update%20procedure%20for%20the%20data%20directory.%0A%0ARead%20the%20whole%20recipe%2C%20closed%20details%20included%2C%20and%20follow%20%22Set%20up%20by%0Ahand%22%20in%20order%2C%20skipping%20VM%20creation%3B%20the%20walkthrough%20above%20it%20is%20for%0Athe%20owner.%20Use%20the%20pinned%20image%20tag%20as%20written.%20Never%20make%20the%20VM%20public%3A%0Athe%20first%20person%20to%20finish%20Executor%27s%20setup%20page%20becomes%20its%20owner%2C%20and%0Athat%20must%20be%20the%20owner.%20Don%27t%20set%20EXECUTOR_APPS_ALLOW_PRIVATE_FETCH%20unless%0Athe%20owner%20asks.%20On%20an%20existing%20VM%2C%20ask%20before%20replacing%20anything%20on%20port%0A8000.%20The%20VM%20can%27t%20reach%20its%20own%20https%3A%2F%2F%3Cvm%3E.exe.xyz%2C%20so%20checks%20use%0Alocalhost.%20Finish%20by%20sending%20the%20owner%20to%20https%3A%2F%2F%3Cvm%3E.exe.xyz%2F%20to%20create%0Atheir%20account%2C%20then%20to%20%22Add%20your%20tools%22%20and%20%22Connect%20your%20agents%22%2C%20with%20the%0A%60ssh-key%20generate-api-key%60%20command%20to%20run%20on%20their%20computer.%0A%0AFinish%20with%20the%20URLs%20I%20should%20open%20and%20these%20commands%2C%20which%20only%20I%20can%20run%2C%20from%20my%20own%20computer%20%28with%20this%20VM%27s%20name%20in%20them%29%3A%0A%20%20ssh%20exe.dev%20ssh-key%20generate-api-key%20--vm%3Dmy-executor%20--label%3Dexecutor-agents%20--exp%3D90d%0A to create a VM whose agent, Shelley, follows this recipe. From a terminal:

```sh
curl -fsSL https://exe.dev/deploy/executor/prompt.txt | ssh exe.dev new --prompt=/dev/stdin
```

Then, on your own computer:

```sh
ssh exe.dev ssh-key generate-api-key --vm=my-executor --label=executor-agents --exp=90d
```

Or follow the steps below by hand.

[Executor](https://executor.sh) is an open-source gateway between your agents
and your tools. You add MCP servers, OpenAPI and GraphQL APIs, and accounts
such as Gmail or GitHub to it once; it keeps their credentials and asks
before risky calls. Every agent then connects to one MCP endpoint and finds
the tool it needs by searching, instead of loading hundreds of tool
definitions into its context. Executor 2, in beta, goes further: an agent
can write new tools for you, with storage, schedules and webhooks, and they
keep running on the server.

A VM makes a good home for it: always on, with HTTPS and a disk for the
catalog and credentials. exe.dev's proxy keeps it private, which matters
more than usual here. Executor 2 has no admin password to preset: the first
person to finish its setup page owns the server. Behind your exe.dev login,
that can only be you.

## Add your tools

Open `https://my-executor.exe.xyz/` and create your account: an
organization name, your name, an email and a password. Skip **Connect your
accounts** for now.

On **Apps**, choose **Add app**:

- **From an MCP server** takes a remote MCP server's URL. Try
  `https://mcp.deepwiki.com/mcp`: Executor finds its three tools and makes
  an app of them. Servers that need a sign-in use OAuth, from the app's
  **Accounts** tab.
- **Browse app catalog** lists ready-made apps such as Gmail, GitHub, Linear
  and Stripe. Some need an OAuth client of your own; give the provider
  `https://my-executor.exe.xyz/api/oauth/callback` as its redirect URL.
- **From scratch** gives you a prompt for your agent, which then writes the
  app: for an OpenAPI or GraphQL API, a service with an API key, or a tool of
  your own.

Each app is TypeScript code you can read on its **Source** tab. Apps made
from an MCP server ask for your approval before any tool the server marks
as destructive; edit that rule there.

## Connect your agents

Each agent sends two headers:

- `X-Exedev-Authorization: Bearer exe1.…`, a [VM token](/docs/https-tokens-for-vms)
  that gets it through exe.dev's proxy, which removes it before Executor
  sees the request.
- `Authorization: Bearer exp_…`, an Executor personal access token.

Make the VM token on your computer (`--exp` sets when it expires):

```bash
ssh exe.dev ssh-key generate-api-key --vm=my-executor --label=executor-agents --exp=90d
```

For the Executor token, open your avatar menu → **Account settings** →
**Tokens** → **Create token**, name it after the agent, and limit it to
your organization. It's shown once. Below, replace `exe1.paste-yours-here`
and `exp_paste-yours-here` with yours.

**Claude Code**, on your computer or a VM like the one in
[Claude Code on exe.dev](/deploy/claude-code):

```bash
claude mcp add --transport http --scope user executor https://my-executor.exe.xyz/mcp \
  --header "X-Exedev-Authorization: Bearer exe1.paste-yours-here" \
  --header "Authorization: Bearer exp_paste-yours-here"
claude mcp list
```

Expect `executor: https://my-executor.exe.xyz/mcp (HTTP) - ✔ Connected`.

**Codex**, on your computer or a [Codex VM](/deploy/codex), in
`~/.codex/config.toml`:

```toml
[mcp_servers.executor]
url = "https://my-executor.exe.xyz/mcp"
http_headers = { "X-Exedev-Authorization" = "Bearer exe1.paste-yours-here", "Authorization" = "Bearer exp_paste-yours-here" }
```

**Shelley**, on any of your VMs:

```bash
shelley mcp add executor -d "Executor: my apps and tools" \
  -H "X-Exedev-Authorization: Bearer exe1.paste-yours-here" \
  -H "Authorization: Bearer exp_paste-yours-here" \
  https://my-executor.exe.xyz/mcp
shelley mcp call executor.search query=deepwiki
```

**Other clients:** any MCP client that speaks Streamable HTTP and can send
headers works the same way. An agent on the Executor VM itself can skip the
VM token and use `http://localhost:8000/mcp`.

> [!TIP]
> For agents on your other exe.dev VMs, a
> [VM-to-VM integration](/docs/integrations-vm-to-vm) can add both headers
> at exe.dev's edge, so no token is stored on the agent's VM. On your
> computer, for an agent on `my-hermes-agent`:
> `ssh exe.dev integrations add http-proxy --name executor-hermes --target https://my-executor.exe.xyz/ --peer --bearer exp_paste-yours-here --attach vm:my-hermes-agent`.
> The agent's URL is then `https://executor-hermes.int.exe.xyz/mcp`, with no
> headers.

## Try it

Ask your agent:

> Use executor to find out how the UsefulSoftwareCo/executor repository is
> structured.

It searches Executor's catalog, finds the DeepWiki tools, and calls one.
The six tools an agent sees are always the same (`search`, `describe`,
`call`, `execute`, `resume`, `skills`); the apps behind them are what you
add. To have an agent add one:

> Use executor to add an app for the Linear API.

When a call needs your approval, the agent shows you the request and
passes on your answer.

## Keys off the VM

API keys you give Executor stay in its encrypted database, not in your
agents. To keep some off the VM entirely, use an exe.dev
[integration](/docs/integrations): exe.dev holds the secret and adds it at
its edge when the VM calls `https://<name>.int.exe.xyz`. Executor's app
sandbox refuses private addresses, which these are, until you allow them in
`~/executor/compose.yaml`, under `environment`:

```yaml
      EXECUTOR_APPS_ALLOW_PRIVATE_FETCH: "true"
```

Then run `docker compose up -d` in `~/executor`, and ask your agent for an
app that calls `https://<name>.int.exe.xyz` with no credentials.

> [!WARNING]
> This applies to every app, not just one: any app can then reach every
> integration attached to the VM and services on the VM itself. Allow it
> only if you read the apps your agents write.

## Cloud agents

claude.ai, ChatGPT, and agents running in their makers' clouds can't send an
exe.dev token, so they can reach only a public VM. Executor then is the only
lock, and a real one: `/mcp` refuses requests without a token, and clients
sign in with OAuth in your browser, which needs your Executor password and
your approval. Create your account first, then, on your computer:

```bash
ssh exe.dev share set-public my-executor
```

Add `https://my-executor.exe.xyz/mcp` to the app as a custom connector and
sign in. Claude Code (`/mcp`) and Codex (`codex mcp login executor`) can sign
in the same way. OAuth connections can also be limited to some apps: on
**Connections**, make a connection and use its MCP URL.

> [!WARNING]
> Public means Executor's sign-in page faces the internet. Use a strong
> password, approve only connections you just started, and go back with
> `ssh exe.dev share set-private my-executor` when you're done.

## The nuts and bolts

Happy with what Shelley set up? Stop here. Below are the steps it
followed, and maintenance for later.

<details id="create-the-vm" data-manual-setup class="dp-details">
<summary>Set up by hand</summary>

### Create the VM

On your computer (pick another name if `my-executor` is taken):

```bash
ssh exe.dev new --name=my-executor
ssh my-executor.exe.xyz
```

Everything else runs **on the VM**.

### Run Executor

Executor's official image listens on port 4400; Compose publishes it on
8000, where exe.dev's proxy sends `https://<vm>.exe.xyz/`.
`BETTER_AUTH_URL` must be exactly that address, or sign-in fails. The
catalog feed fills **Browse app catalog**, and `DO_NOT_TRACK` turns off the
anonymous usage events that released images send by default:

```bash
mkdir -p ~/executor && cd ~/executor
echo "BETTER_AUTH_URL=https://$(hostname).exe.xyz" > .env
cat > compose.yaml <<'EOF'
services:
  executor:
    image: ghcr.io/usefulsoftwareco/executor-selfhost:2.0.0-beta.34
    init: true
    restart: unless-stopped
    ports:
      - "8000:4400"
    environment:
      BETTER_AUTH_URL: ${BETTER_AUTH_URL}
      EXECUTOR_CATALOG_URL: https://catalog.executor.sh/index.json
      DO_NOT_TRACK: "1"
    volumes:
      - ./data:/app/data
    stop_grace_period: 30s
EOF
sudo systemctl enable --now docker.service
docker compose up -d
```

On first start, Executor creates its database and two keys,
`auth-secret.key` and `encryption.key`, in `~/executor/data`.

### Check it

```bash
until curl -fsS http://localhost:8000/health; do sleep 2; done; echo
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:8000/mcp
```

Expect `{"status":"ok"}`, then `401`: the MCP endpoint wants a token. Then
open `https://my-executor.exe.xyz/` and create your account, as in
[Add your tools](#add-your-tools).

</details>

<details class="dp-details">
<summary>Back up and restore</summary>

Everything is in `~/executor/data`: the database, both key files, and your
apps' code. Stop Executor for a consistent copy:

```bash
cd ~/executor
docker compose stop
(umask 077; tar -czf - data compose.yaml .env > ~/executor-$(date -u +%Y%m%d).tar.gz)
docker compose start
```

The archive holds the keys, so it's readable only by you. Copy it off the
VM too. To restore one:

```bash
cd ~/executor
docker compose stop
rm -rf data
tar -xzf ~/executor-20261031.tar.gz -C ~/executor
docker compose start
```

A backup without the key files can't be opened.

</details>

<details class="dp-details">
<summary>Update</summary>

Back up first. Then change the tag in `~/executor/compose.yaml` to the
[newest release](https://github.com/UsefulSoftwareCo/executor/releases)
(`2.0.0-beta.35`, for example) and recreate the container:

```bash
cd ~/executor
docker compose pull && docker compose up -d
```

Executor migrates its data on startup. To follow every beta without editing
the file, use the `beta` tag instead.

</details>

<details class="dp-details">
<summary>Troubleshooting</summary>

- **Sign-in loops or fails:** `BETTER_AUTH_URL` in `~/executor/.env` isn't
  exactly `https://<vm>.exe.xyz`. Fix it and `docker compose up -d`.
- **An agent gets `401`:** without `X-Exedev-Authorization`, exe.dev
  refuses it; with it, Executor wants `Authorization: Bearer exp_…`. Check
  both, the `Bearer` before each, and that neither has expired.
- **"Could not reach this MCP server":** Executor fetches the URL from the
  VM. Check it from there with `curl -i <url>`.
- **Logs:** `docker compose -f ~/executor/compose.yaml logs --tail 100`.

</details>

## Frequently asked questions

### Executor 1 or Executor 2?

This page runs Executor 2, which is in beta and is what [executor.sh](https://executor.sh) and its docs now describe: apps with tools, skills, storage, schedules and webhooks. The 1.x line (1.6.11 on Oct 22, 2026) is still the `latest` image tag and npm release, with its own data format; 2.0 doesn't upgrade a 1.x install in place. Betas come out almost daily, so the page pins one tag.

### What does it cost?

Executor is MIT-licensed and runs no model of its own, so just your [VM plan](https://exe.dev/pricing). Your agents' model use bills wherever those agents run.

### Who can reach it?

exe.dev's proxy lets in only you (signed in) and holders of a VM token for this VM, then Executor wants its own sign-in or token. A leaked Executor token is useless without a VM token, and the reverse.

### Where are my API keys and OAuth tokens kept?

In Executor's database on the VM, encrypted with `encryption.key` in the same data directory. Agents get tools, never the credentials behind them. Back up the whole directory: without the key files, Executor won't start.

### Does it phone home?

Released images send anonymous usage events (counts, timings, error types; never tool inputs, outputs or credentials) to the Executor team by default. This page turns that off with `DO_NOT_TRACK: "1"` in `compose.yaml`; remove the line to send them.

### Can claude.ai or ChatGPT use it?

Only if the VM is public, since they connect from their makers' servers. See [Cloud agents](#cloud-agents).


## Related

- [Give any agent a sandbox over MCP](https://exe.dev/deploy/exe-mcp.md): One URL gives your agent real VMs to run code on, host apps from, and hand work to.
- [Host a remote MCP server](https://exe.dev/deploy/mcp-server.md): Tools for all your agents, on a computer of their own. Private until you say.
- [Self-host GBrain, shared memory for your agents](https://exe.dev/deploy/gbrain.md): One memory for every agent you run, behind two locks.
- [Run Claude Code on a remote server](https://exe.dev/deploy/claude-code.md): A computer for Claude. A breather for your laptop.
- [Run Codex on a remote server](https://exe.dev/deploy/codex.md): A computer for Codex. An early night for your laptop.
- [Host OpenClaw](https://exe.dev/deploy/openclaw.md): An AI sidekick with its own computer. Your laptop can take a nap.
