---
sidebar_position: 2
question: How do I start the full Compose stack on one machine?
kind: task
via_web: na
via_cli: available
via_python: na
via_api: na
via_config: available
ref_cli: abi stack start
ref_config: docker-compose.yml
prereq: A project made by `abi new project`, and [Docker](https://docs.docker.com/get-docker/) with Compose v2 and 8 GB of RAM or more. See [Install and prerequisites](/v2/capabilities/get-started/install).
next:
  - /v2/capabilities/deploy/dokploy
  - /v2/capabilities/deploy/production
  - /v2/capabilities/deploy/add_secrets_to_production
---

> **You are reading the v2.x docs (engine modules). New projects use v3.** [Read this page in v3](/capabilities/deploy/local-docker) · [Migrate from 2.x to 3.0](/capabilities/upgrade/migrate-to-3)

# Deploy with Docker

`abi deploy local` writes a Docker Compose stack for your project, and `abi stack start` runs it. It is the way to run the full set of backing services (PostgreSQL, Fuseki, Qdrant, MinIO, Redis) on one machine: a laptop, a workstation, a single server. For a server with a domain and certificates, use [Dokploy](/v2/capabilities/deploy/dokploy) (ABI 3.x) or the [production guide](/v2/capabilities/deploy/production).

Your modules run inside the stack's `abi` service: the engine loads every module listed under `modules:` in `config.local.yaml`. There is nothing else to deploy for them.

`abi new project` already writes the stack, unless you passed `--without-local-deploy`. The stack's `abi` service runs with `ENV=local`, so it reads `config.local.yaml`: PostgreSQL for the document service, Fuseki for the triple store, Qdrant, MinIO and Redis. `config.yaml` is what `abi dev up` reads. See [Configuration](/user-guide/get-started/configuration#environment-files).

## Web UI

Not applicable. Nexus runs inside the stack, so it cannot write or start it. Use the CLI, or run the generated files with Docker Compose (Config).

## CLI

### Write the stack

From the root of the project:

```bash
abi deploy local                        # asks for the base domain: localhost by default
abi deploy local --regenerate           # re-render from the CLI's current templates
```

It writes `docker-compose.yml`, `.deploy/docker/` (Caddy, Postgres init scripts, and on ABI 3.x the NATS broker's `nats.conf`) and the variables the stack needs in `.env`: generated passwords (PostgreSQL, MinIO, RabbitMQ, Fuseki), the admin's password (`NEXUS_USER_ADMIN_EXAMPLE_COM_PASSWORD`) and `ABI_API_KEY`. On ABI 3.x it also writes the broker's `NATS_JWT_SECRET` and `NATS_ABI_PASSWORD`.

- **ABI 2.x**: the stack has Dagster and RabbitMQ; there is no NATS.
- **ABI 3.x, a project with a `nats:` block** in its config: the **NATS stack**, a `nats` service the engine waits for, no Dagster, and RabbitMQ only behind the Compose profile `rabbitmq`.
- **ABI 3.x, a project without one**: the classic stack ([legacy](/user-guide/get-started/legacy-mode): Dagster, RabbitMQ), and `abi deploy local` adds the `naas-abi-core[dagster,rabbitmq]` extras to its `pyproject.toml`: commit the change.
- `--regenerate` backs the previous files up first (`--no-backup` skips it), keeps the values already in `.env`, and never touches `docker-compose.override.yml`. Regenerate after each CLI upgrade.
- Optional extras: `--coding` (Coder, Forgejo and Actions CI workspaces) and `--headscale` (a Headscale service).

### Start it

```bash
abi stack start
```

It runs `docker compose up -d` (on ABI 3.x it first writes the broker's passwords and signing secret to `.env` when they are missing), checks for containers that exited or are unhealthy (retrying up to twice, and printing the failing services' logs), then opens the Nexus sign-in page. It does not wait for every service to be ready: the first start pulls the images and builds `abi`, and the engine then loads every module and runs the Nexus migrations. Allow a few minutes.

### Check it

```bash
abi stack status                        # state of each service
abi stack logs abi                      # logs of one service (no argument: all)
abi stack tui                           # a live terminal view
```

`abi start`, `abi stop` and `abi logs` are shortcuts. `abi deploy local-up -d`, `abi deploy local-logs` and `abi deploy local-down [-v]` call `docker compose` with the files passed explicitly.

### Sign in

Open Nexus at `http://localhost:3042` and sign in as `admin@example.com` with the password from `.env`:

```bash
grep NEXUS_USER_ADMIN_EXAMPLE_COM_PASSWORD .env
```

### Stop it

```bash
abi stack stop                          # stop; -v also removes the volumes
```

## Python

Not applicable. There is no Python call that writes or starts the stack. Use the CLI, or Docker Compose (Config).

## REST API

Not applicable. The API runs inside the stack: it cannot start it. Use the CLI, or Docker Compose (Config).

## Config

The stack is plain Docker Compose. Once the files exist, you can edit them and run them with `docker compose` yourself. The first render still needs the CLI: `abi new project` or `abi deploy local`.

### Edit the files you own

| File | What it holds | Rewritten by `--regenerate` |
|---|---|---|
| `config.local.yaml` | The engine's services, modules and secrets for this stack | No |
| `.env` | Generated passwords and keys, and your own secrets | No (values are kept) |
| `docker-compose.override.yml` | Your own changes to any service (you create it) | No |
| `docker-compose.yml`, `.deploy/docker/` | The services, Caddy, Postgres init, `nats.conf` (ABI 3.x) | Yes |

Put your changes to a service in `docker-compose.override.yml`, not in `docker-compose.yml`:

```yaml title="docker-compose.override.yml"
services:
  abi:
    environment:
      - LOG_LEVEL=INFO
```

### Start the stack

```bash
docker compose up -d
```

Compose reads `docker-compose.yml` and merges `docker-compose.override.yml`, as `abi stack start` does. It does not write missing secrets: `abi deploy local` already put them in `.env`.

### Follow it

```bash
docker compose ps
docker compose logs -f abi
```

### Stop it

```bash
docker compose down                     # -v also removes the volumes
```

## Services

| Service | Where |
|---|---|
| Nexus web | http://localhost:3042 (or `nexus.<domain>` through Caddy) |
| API (Swagger at `/docs`) | http://localhost:9879 (or `api.<domain>`) |
| NATS monitoring (ABI 3.x, NATS project) | http://localhost:8222 (this machine only) |
| RabbitMQ management (ABI 2.x, and 3.x without NATS) | http://localhost:15672 |
| Fuseki (SPARQL) | http://localhost:3030 |
| MinIO console | http://localhost:9001 |
| MCP server | http://localhost:8000 (this machine only on ABI 3.x; every interface on 2.x) |
| Service portal, YasGUI, Redis Commander | http://localhost:8080, 3000, 8082 |

The generated file publishes most of these ports on every interface of the host, for development. On a shared server, firewall them so that only Caddy (80, 443) is reachable. See [Security and compliance](/v2/capabilities/deploy/security-compliance).

## Models: Ollama on Linux

A stack that uses [Ollama](https://ollama.com) reaches the host through `host.docker.internal`. On Linux, Ollama listens on `127.0.0.1` only, which the Docker bridge cannot reach: bind it to an address the bridge can reach (`OLLAMA_HOST=0.0.0.0:11434` on a trusted network, or the bridge address and a firewall rule), then restart it. Docker Desktop on macOS needs nothing. To use an Ollama elsewhere, set `ABI_OLLAMA_BASE_URL`.

## Snapshots

```bash
abi stack snapshot create -m "before upgrade"
abi stack snapshot list
abi stack snapshot restore <id>         # destructive; takes a safety snapshot first
abi stack snapshot export <id> backup.tar.gz
abi stack snapshot import backup.tar.gz
abi stack snapshot prune --keep 5
```

A snapshot archives the data volumes (including `rabbitmq_data`, and `nats_data` on ABI 3.x) and `storage/`. See [High availability](/v2/capabilities/deploy/high-availability#snapshots-of-the-docker-stack).

## Reset

```bash
abi stack stop -v                       # removes the volumes: the data is gone
```

:::tip Password refused after a reset?
If "Incorrect email or password" appears after a reset, read the password again from `.env`: it may have just been rotated.
:::
