# Self-hosting quickstart

Ivy runs anywhere Docker runs. One `docker compose up` starts the ingest router, the OpenTelemetry Collector, ClickHouse, and the API with the dashboard and MCP server. It is MIT licensed and has no limits.

## Start it

```
git clone https://github.com/ivytrace/ivy && cd ivy
docker compose -f deploy/docker-compose.yml up -d --build
```

| Service | Address |
|---|---|
| Dashboard, API and MCP server | `http://localhost:3000` (API at `/api`, MCP at `/mcp`) |
| OTLP/HTTP ingest | `http://localhost:4318/v1/traces`, with `Authorization: Bearer <key>` |
| ClickHouse HTTP | `http://localhost:8123` |

On startup Ivy creates a `default` workspace, its `default` project and an ingest key (`IVY_INGEST_API_KEY`, `dev-ingest-key` unless you set it). Stop with `docker compose -f deploy/docker-compose.yml down` (add `-v` to delete the data).

## Settings that matter

Set these in your shell or in `deploy/.env`. **Change the defaults before exposing Ivy to a network.**

| Variable | Default | |
|---|---|---|
| `IVY_INGEST_API_KEY` | `dev-ingest-key` | Key of the default project |
| `IVY_COLLECTOR_TOKEN` | `dev-collector-token` | Shared secret between the ingest router and the collector |
| `IVY_CLICKHOUSE_USER`, `IVY_CLICKHOUSE_PASSWORD` | `ivy`, `ivy` | ClickHouse credentials |
| `IVY_RETENTION_DAYS` | `30` | How long traces are kept (set before the first start) |
| `IVY_PUBLIC_URL` | | The URL people use to reach Ivy |
| `IVY_INGEST_PUBLIC_URL` | | The ingest URL your Lambda functions can reach (needed for auto-trace) |
| `IVY_SECRET_KEY` | | Encrypts per-project auto-trace keys |

The [deploy README](https://github.com/ivytrace/ivy/blob/main/deploy/README.md) lists every variable.

## Sign-in with OIDC

Without OIDC, the dashboard, API and MCP server run open (for setups behind your own authenticating proxy) and the dashboard shows an "authentication disabled" banner. To require sign-in:

1. Register a public SPA client with your provider (Keycloak, Auth0, Okta, Entra ID, Authentik, Zitadel, …) with the redirect URI `<your URL>/auth/callback`, and an API audience whose access tokens are JWTs.
2. Set `IVY_OIDC_ISSUER` and `IVY_OIDC_CLIENT_ID` (and `IVY_OIDC_AUDIENCE` if it differs from the client ID).
3. For several workspaces with members and invitations, set `IVY_SINGLE_TENANT=0`. For invitation emails, set `IVY_SMTP_URL` and `IVY_EMAIL_FROM`.

Ivy never uses passwords of its own.

## Send traces

- **Lambda, by hand:** build and publish the layer ([layer README](https://github.com/ivytrace/ivy/blob/main/packages/layer/README.md)), then set `IVY_ENDPOINT` to your ingest URL and `IVY_API_KEY` to a project key ([manual setup](https://ivytrace.dev/docs/manual-setup)).
- **Lambda, with auto-trace:** give Ivy an AWS identity (`IVY_AWS_PRINCIPAL_ARN` and AWS credentials) that can assume the role the CloudFormation template creates, and set `IVY_INGEST_PUBLIC_URL`. Then connect accounts in the dashboard. Without a hook that publishes templates, the dashboard offers the template as a download.
- **Anything else:** any OpenTelemetry SDK, over OTLP/HTTP to port 4318 ([OpenTelemetry](https://ivytrace.dev/features/opentelemetry)).

## Alerts

Turn on Slack and the weekly digest with environment variables, and use the `on-error-group-created` hook for anything else. See [setting up alerts](https://ivytrace.dev/docs/alerts).

## Agents

Point your agent at your instance: `claude mcp add --transport http ivy https://ivy.example.com/mcp`, and tell it to use your URL instead of `https://ivytrace.dev` when following `llms.txt`.

## Updating

Pull the new version, apply the schema (it is idempotent) and restart:

```
git pull
docker compose -f deploy/docker-compose.yml up -d --build
docker compose -f deploy/docker-compose.yml exec -T clickhouse /docker-entrypoint-initdb.d/init.sh
```

---

Source: https://ivytrace.dev/docs/self-hosting · Updated 2026-11-14
