Self-hosting

Quickstart

Run Eddytor on your own machine or server with one command. Prebuilt images — nothing to clone, nothing to build.

3 min read

Eddytor is free to self-host. Everything you need is Docker and one command — the installer brings a bundled Postgres and Garage (an S3-compatible object store) so you can evaluate without setting anything else up.

Install

curl -fsSL https://get.eddytor.com | sh

The installer creates an install directory (~/eddytor), generates secrets into .env, starts the stack, and walks you through creating the first admin. That directory is yours:

~/eddytor/
├── docker-compose.yml   # replaced on upgrade — don't edit
├── config.toml          # non-secret settings (public URL, CORS, …) — edit this
├── HOSTING.md           # the full self-hosting guide
└── .env                 # secrets + bundled-stack wiring (generated) — back this up
Back up .env

Losing EDDYTOR_ENCRYPTION_KEY makes every stored secret unrecoverable. Keep a copy of .env somewhere safe.

Eddytor is API-first

http://localhost:8080 is the REST + gRPC API, not a UI. You operate Eddytor with the CLI, the API, or MCP. An optional web UI is one prompt away — see Web UI.

Create the first admin

The installer prompts you for this. To do it by hand, run the setup tool inside the server container — there is no public setup endpoint and no token to leak:

docker compose exec eddytor-server eddytoradm setup \
  --email you@example.com --org "Default"

It's idempotent — a no-op once an admin exists. Sign-in is passwordless (magic link); with no SMTP configured the link is printed to the server logs instead of emailed.

Install the CLI

# macOS / Linux (Homebrew)
brew install eddytor-labs/tap/eddytor

# macOS / Linux (shell)
curl -fsSL https://raw.githubusercontent.com/eddytor-labs/eddytor-cli/main/install.sh | sh

# Windows (Scoop)
scoop bucket add eddytor https://github.com/eddytor-labs/eddytor-cli
scoop install eddytor

Point it at your install and sign in:

eddytor config set-api-url    http://localhost:8080
eddytor config set-flight-url http://localhost:8082
eddytor login                 # device-code flow; opens your browser
eddytor get tables
eddytor query "SELECT 1"
Prefer a headless key?

Mint a non-expiring API key from inside the container: docker compose exec eddytor-server eddytoradm create-api-key --email you@example.com, then eddytor config set-key edd_live_…. Use the key (not eddytor login) for eddytor query — login tokens expire after 15 minutes.

Connect with MCP

Eddytor exposes an MCP endpoint at ${public_url}/mcphttp://localhost:8080/mcp on a local install. Add it to any MCP-aware client. Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "eddytor": {
      "url": "http://localhost:8080/mcp"
    }
  }
}

Cursor (Settings → MCP Servers):

{
  "eddytor": {
    "url": "http://localhost:8080/mcp"
  }
}

On first use the client triggers an OAuth 2.1 device-code flow — open the URL in your browser, approve, and the client caches the token. No API key to paste.

Create your first table

The installer can do this for you

On a fresh install it offers to register the bundled Garage store and seed a demo demo_products table — accept (or set EDDYTOR_SEED_DEMO=true) and you have a table to query immediately. The steps below are the manual path.

A bucket named eddytor is created in the bundled Garage on boot. Register it as a storage connection, then create tables against it. The credentials are GARAGE_ACCESS_KEY / GARAGE_SECRET_KEY in your .env:

eddytor create storage s3 --bucket eddytor \
  --endpoint http://garage:3900 --region us-east-1 \
  --access-key-id "$GARAGE_ACCESS_KEY" --secret-access-key "$GARAGE_SECRET_KEY"

# then seed a demo table into the new config (id is printed on register):
eddytor create demo-table --config <config-id>

http://garage:3900 is the in-cluster endpoint the engine uses to reach the store — the compose service name, not localhost. Registration probes the store before saving, so a misconfiguration fails fast with a specific reason instead of a generic error. An empty bucket is fine — it registers with 0 tables.

Upgrade

# bump EDDYTOR_VERSION in .env, then:
docker compose pull && docker compose up -d

Change a setting by editing config.toml and running docker compose restart — config is read at boot, not hot-reloaded.

Still stuck? We reply fast.

Can't find it? Ask support and a human will answer, usually within a few hours.