# Docker Compose Archive

> Run a Mina archive node using Docker Compose.

Canonical URL: https://docs.minaprotocol.com/node-operators/archive-node/docker-compose

Run a Mina archive node — a PostgreSQL database that ingests blocks from a connected daemon, started from a published archive dump, plus a missing-blocks guardian that fills gaps from the published precomputed blocks. Use this if you need historical chain state beyond the daemon's transition frontier (the last `k` blocks).

The full Docker Compose configuration — including `docker-compose.yml`, example environment files for mainnet and devnet, a `Makefile`, and a `README` — is maintained in the Mina repository:

**[`mina/src/app/archive/docker-compose/`](https://github.com/MinaProtocol/mina/tree/compatible/src/app/archive/docker-compose)**

## Quick start

:::tip
Before running the commands below, review the [Configuration](#configuration) section to see all available options — including image tags, network selection, ports, and database settings.
:::

```bash
git clone https://github.com/MinaProtocol/mina.git
cd mina/src/app/archive/docker-compose

# For mainnet
cp example.mainnet.env .env

# For devnet
cp example.devnet.env .env

# Edit .env — set MINA_LIBP2P_PASS and review POSTGRES_PASSWORD
vi .env

# Start services
docker compose --env-file .env up -d

# Or use make shortcuts
make mainnet
make devnet
```

:::note
Every `docker compose` command on this page passes `--env-file .env`. Docker Compose reads `.env` on its own, but other runtimes, such as Podman, do not.
:::

:::info
The `bootstrap_db` service runs [mina-provision](https://github.com/MinaProtocol/mina-provision): it downloads the newest hourly archive dump for `MINA_NETWORK` and loads it into PostgreSQL. A mainnet dump is about 1 GiB compressed and several times that after extraction, so the first start takes a while. The archive node and the Mina daemon start after the import completes. On later starts, the database already holds an archive, and `bootstrap_db` leaves it alone without downloading anything.
:::

## Services overview

| Service | Description | Default Port |
|---------|-------------|--------------|
| **postgres** | PostgreSQL 17 with health checks | 5432 (container), configurable host port |
| **bootstrap_db** | One-shot: [mina-provision](https://github.com/MinaProtocol/mina-provision) loads the newest hourly archive dump. Skipped when the database already holds an archive | — |
| **mina_archive** | Archive process, stores block data in PostgreSQL | 3086 |
| **mina_node** | Mina daemon connected to the archive process via `--archive-address` | 3085 (GraphQL), 8302 (P2P) |
| **missing_blocks_guardian** | Fills in the blocks between the restored dump and the chain tip, and any later gaps, from the published precomputed blocks | — |

## Configuration

All configuration is done through a single `.env` file. Key variables:

### Docker images

| Variable | Description |
|----------|-------------|
| `MINA_DAEMON_IMAGE` | Mina daemon Docker image |
| `MINA_ARCHIVE_IMAGE` | Mina archive Docker image |
| `MINA_PROVISION_IMAGE` | [mina-provision](https://hub.docker.com/r/minaprotocol/mina-provision) image, used by `bootstrap_db` |

All images, for mainnet and devnet, are pulled from [Docker Hub](https://hub.docker.com/u/minaprotocol) (`minaprotocol/mina-*`). The example `.env` files pin a tested release of each.

### Database

| Variable | Default | Description |
|----------|---------|-------------|
| `POSTGRES_DB` | `archive` | Database the archive node writes to. Keep `archive`: the published dumps always restore into a database of that name |
| `POSTGRES_USER` | `postgres` | PostgreSQL user |
| `POSTGRES_PASSWORD` | `postgres` | PostgreSQL password. Change it before you expose `POSTGRES_PORT` |

### Network

| Variable | Description |
|----------|-------------|
| `MINA_NETWORK` | `mainnet` or `devnet` |
| `MINA_PEERLIST_URL` | Bootstrap peers URL |
| `MINA_LIBP2P_PASS` | Passphrase for the libp2p key (required) |

### Ports

| Variable | Default | Description |
|----------|---------|-------------|
| `POSTGRES_PORT` | `5433` | Host port mapped to PostgreSQL |
| `MINA_REST_PORT` | `3085` | GraphQL API port |
| `MINA_P2P_PORT` | `8302` | P2P networking port |
| `MINA_ARCHIVE_PORT` | `3086` | Archive server port |

### Archive bootstrap

| Variable | Description |
|----------|-------------|
| `GUARDIAN_PRECOMPUTED_BLOCKS_URL` | Where the missing blocks guardian reads precomputed blocks (the public `mina_network_block_data` bucket) |
| `GUARDIAN_SLEEP_INTERVAL` | Seconds between the guardian's checks (optional, default `600`) |

The dump location is not configured here: mina-provision derives it from `MINA_NETWORK`. To read dumps from a mirror instead, mount a provider file into the `bootstrap_db` service and set `MINA_PROVISION_CONFIG` to its path. See [Writing a provider](https://github.com/MinaProtocol/mina-provision#writing-a-provider).

## Data persistence

Bind mounts preserve data across `docker compose down` / `up`:

| Host path | Container path | Contents |
|-----------|---------------|----------|
| `./archive/postgresql/data` | `/var/lib/postgresql/data` | PostgreSQL data |
| `./archive/data` | `/data` | Archive node data |
| `./mina_node/.mina-config` | `/root/.mina-config` | Daemon config, keys, peers |

## Make targets

| Command | Description |
|---------|-------------|
| `make devnet` | Copy devnet env and start services |
| `make mainnet` | Copy mainnet env and start services |
| `make stop` | Stop services |
| `make clean` | Stop services and remove volumes; prints how to delete the bind-mounted data |
| `make logs` | Follow logs |
| `make status` | Show container status |
| `make health` | Check Postgres, GraphQL endpoint, and container summary |

## Verifying the deployment

Once services are running and the node is synced:

```bash
make health

docker compose --env-file .env exec mina_node mina client status

# Mina node sync status
curl -s http://localhost:3085/graphql -H 'Content-Type: application/json' \
  -d '{"query":"{ syncStatus }"}' | jq .

# Connect to archive database
psql postgres://postgres:postgres@localhost:5433/archive

# Latest block in archive
psql postgres://postgres:postgres@localhost:5433/archive \
  -tAc "SELECT max(height) FROM blocks"

# Missing-blocks guardian progress
docker compose --env-file .env logs --tail=50 missing_blocks_guardian
```

## Clean start

```bash
make clean
docker compose --env-file .env up -d
```

:::warning
`make clean` stops the services and removes the Docker volumes. The database and the daemon's `.mina-config` (including any keys) are bind mounts under `./archive` and `./mina_node`, owned by root, so `make clean` does not delete them: it prints the command that does (`sudo rm -rf ./archive ./mina_node`). After that, the next start downloads and imports the newest archive dump again.
:::
