> For the complete documentation index, see [llms.txt](https://docs.observal.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.observal.io/self-hosting/docker-compose.md).

# Docker Compose setup

Step-by-step bring-up of the Observal stack. End state: the core services are healthy, API responding at `http://localhost/health`, web UI at `http://localhost`. Prometheus and Grafana are optional.

## 1. Clone and configure

```bash
git clone https://github.com/Observal/Observal.git
cd Observal
cp .env.example .env
```

The `.env.example` ships with working direct-value defaults for local source development, including demo account credentials. You do not need to edit it for local development. Production server-package installs use generated files under `secrets/` instead; see [Configuration](/self-hosting/configuration.md#secret-files).

> \[!NOTE] You need Docker Engine ≥ 24.0 with Compose v2 (`docker compose`, not `docker-compose`). Homebrew's Docker formula is outdated. Install [Docker Desktop](https://docs.docker.com/get-docker/) or use your distro's upstream packages. Verify with `docker version` and `docker compose version`.

## 2. Start the stack

Core stack only:

```bash
docker compose -f docker/docker-compose.yml up --build -d
```

With Prometheus only:

```bash
docker compose -f docker/docker-compose.yml -f docker/docker-compose.observability.yml up --build -d
```

With Prometheus and Grafana:

```bash
COMPOSE_PROFILES=grafana docker compose -f docker/docker-compose.yml -f docker/docker-compose.observability.yml up --build -d
```

First build takes a few minutes (pulls images, builds `observal-api` and `observal-web`). Subsequent starts are fast.

## 3. Verify health

```bash
docker compose -f docker/docker-compose.yml ps
```

Every service should show `healthy` or `running`. The API waits for Postgres, ClickHouse, and Redis to pass health checks before starting. Expect 15–30 seconds on first boot.

Hit the health endpoint:

```bash
curl http://localhost/health
# {"status":"ok"}
```

## 4. Configure TLS (production only)

For local dev, `http://localhost` is fine. For production, put a TLS-terminating reverse proxy in front of the nginx LB. See [Requirements → TLS / HTTPS](/self-hosting/requirements.md#tls--https).

## 5. Bootstrap the first user

### Option A - demo accounts (fastest for trying it out)

`.env.example` seeds four demo accounts on first startup:

| Role        | Email                   | Password            |
| ----------- | ----------------------- | ------------------- |
| Super Admin | `super@demo.example`    | `super-changeme`    |
| Admin       | `admin@demo.example`    | `admin-changeme`    |
| Reviewer    | `reviewer@demo.example` | `reviewer-changeme` |
| User        | `user@demo.example`     | `user-changeme`     |

Log in with the CLI:

```bash
curl -fsSL https://raw.githubusercontent.com/Observal/Observal/main/install.sh | bash   # if you haven't already
observal auth login              # Email: super@demo.example, Password: super-changeme
```

**Remove demo accounts before real deployment.** Unset the `DEMO_*` env vars in `.env` and restart. Already-seeded accounts stay until you delete them manually (`observal admin delete-user <email>`).

### Option B - fresh bootstrap (recommended for production)

Remove `DEMO_*` from `.env` and start the stack. Run:

```bash
observal auth login
# Server URL: http://localhost
# No users detected - bootstrapping admin account.
# Email: alice@your-company.com
# Password: **************
```

The CLI detects that no users exist and interactively creates the first admin. The `/api/v1/auth/bootstrap` endpoint is restricted to localhost access for security.

## 6. Verify with the CLI

```bash
observal auth whoami
observal auth status

observal registry mcp list         # empty list - you haven't added anything yet
```

## 7. Stop, restart, rebuild

```bash
# Stop core and any optional monitoring containers
make down

# Stop and delete all data, including optional monitoring volumes
docker compose -f docker/docker-compose.yml -f docker/docker-compose.observability.yml --profile grafana down -v

# Restart one service
docker compose -f docker/docker-compose.yml restart observal-api

# Rebuild after code changes
docker compose -f docker/docker-compose.yml up --build -d observal-api
```

Makefile shortcuts from the repo root:

```bash
make logs                  # tail core service logs
make rebuild               # rebuild and restart core services
make up-prometheus         # start core services with Prometheus
make up-observability      # start core services with Prometheus and Grafana
make rebuild-prometheus    # rebuild core services with Prometheus
make rebuild-observability # rebuild core services with Prometheus and Grafana
```

## 8. Logs

```bash
docker compose -f docker/docker-compose.yml logs -f                # all
docker compose -f docker/docker-compose.yml logs -f observal-api   # one service
```

## 9. Port conflicts

If `docker compose up` fails with `port is already allocated`, remap host ports via env vars:

```bash
POSTGRES_HOST_PORT=5433 REDIS_HOST_PORT=6380 \
  docker compose -f docker/docker-compose.yml up --build -d
```

Every host port is configurable. See [Ports and volumes](/self-hosting/ports-and-volumes.md) for the full list.

## Next

→ [Configuration](/self-hosting/configuration.md): which env vars to change for production.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.observal.io/self-hosting/docker-compose.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
