---
title: "Run a node"
description: "Start one Queen node with Docker or from source: what it needs, what lives in its data directory, what it survives, and how to upgrade it. The front door of the Operate section."
---

> Queen MQ documentation, for AI agents
> Complete self-contained summary of Queen MQ: https://queenmq.com/llms-brief.txt
> Fetch that first when the question is about the product rather than about this page.
> Index of all pages: https://queenmq.com/llms.txt

# Run a node

A Queen node is one process and one directory. It serves the HTTP API, the dashboard and its
metrics on port 6632, keeps everything it knows in its data directory, and needs nothing else
running beside it: no database and no coordinator. One node is enough for development and for a
good share of production loads, and when you need failover, a cluster is the same binary three or
five times.

## Start it

### Docker

```bash
docker run --platform linux/amd64 -d --name queen -p 6632:6632 \
  -v queen-data:/var/lib/queen/raft \
  ghcr.io/queen-mq/queen:latest
```
### Compose

```yaml
services:
  queen:
    image: ghcr.io/queen-mq/queen:latest
    ports: ["6632:6632"]
    volumes:
      - queen-data:/var/lib/queen/raft
    stop_grace_period: 60s
volumes:
  queen-data:
```
### From source

```bash
git clone https://github.com/queen-mq/queen && cd queen
(cd app && npm ci && npm run build)    # the dashboard, Node 24; it lands in server/webapp/dist
cd server && cargo build --release     # Rust 1.88 or later; embeds the dashboard
QUEEN_RAFT_DIR=./data ./target/release/queen
```

```bash
curl -s localhost:6632/health
```

```json
{"status":"healthy","engine":"raft","version":"2.0.0-beta.6","raft":{"role":"leader","leader":true,"term":1,"applied":0,"commit":0,"lag":0,"storageReady":true,"clusterVersion":3,"kinds":3}}
```

The dashboard is at `http://localhost:6632/`, and the image carries the CLI, so
`docker exec -it queen queenctl status` works out of the box ([queenctl](/reference/queenctl/)).
Pin a version tag in production; `latest` moves.

## The settings a first node needs

| Variable | Default | What it does |
|---|---|---|
| `PORT` | `6632` | The HTTP port: API, dashboard, `/health`, metrics |
| `QUEEN_BIND_ADDR` | `0.0.0.0` | The host the port binds. A host only; a value with a port stops the boot |
| `QUEEN_RAFT_DIR` | `/var/lib/queen/raft` | The data directory. Put it on a persistent volume |
| `QUEEN_RAFT_DISK_HIGH_PCT`, `QUEEN_RAFT_DISK_LOW_PCT` | `85`, `80` | Above the high mark, writes that grow storage answer `507 storage_full`; they resume below the low one |
| `JWT_ENABLED` | `false` | The broker's own authentication. Off, every route answers any caller ([security](/operate/security/)) |
| `QUEEN_ENCRYPTION_KEY` | unset | 64 hex characters: payload encryption for the queues that ask for it |
| `LOG_LEVEL`, `QUEEN_LOG_JSON` | `info`, `false` | Log verbosity, and one JSON object per line |
| `QUEEN_SERVER_ID` | `HOSTNAME` | The node's name in the dashboard and the logs |

Booleans accept `true/false`, `1/0`, `yes/no` and `on/off`, and any other value stops the boot with
the variable's name, so a typo never quietly becomes a default. The node prints its effective
configuration at boot, one line per area with secrets masked, which is the first thing to read
when a setting does not seem to apply:

```text
INFO boot: config: storage data_dir=/var/lib/queen/raft ready_lag_ms=2000 disk_high_pct=85.0 disk_low_pct=80.0 planner_queue_depth=1024
INFO boot: config: auth enabled=false algorithm=HS256 secret=<unset> public_key=<unset> jwks_url= issuer= audience= clock_skew_s=30 skip_paths=["/health", "/metrics/prometheus", "/metrics", "/"]
```

Every variable is in [configuration](/reference/configuration/).

## The data directory

Everything the node knows is under `QUEEN_RAFT_DIR`, on one volume. The queue logs in `qlog/` hold
the message payloads, written and fsynced once. `store/data.mdb` is the embedded ordered store:
queues, partitions, consumer positions, leases, KV, timers, the dedup index and, with the
[proxy](/operate/tenants/) on, its tenants, users and API-key hashes. A single node keeps its
replication log in `log/`; a cluster node keeps its vote and membership in `raft/` instead.
`local.db` and `dash.db` are this node's own metrics history and dashboard rows.

Never delete files inside the data directory to free space. A missing queue-log file is not
detected at boot, so the node comes up and serves holes. Grow the volume instead.

## What one node survives

| Event | What happens |
|---|---|
| kill -9, a crash, out of memory | Restart it on the same directory. Every acknowledged write is there, because a write is answered only after its fsync |
| Power loss | The same |
| The process is down | Nothing is served. Clients get connection errors and retry |
| The disk is lost | Everything is lost, unless you restore a snapshot of the volume ([backups and restore](/operate/recovery-backups/)) |
| The disk passes 85% | Writes that grow storage answer `507`, while reads, acks and deletes keep working |

Ephemeral queues live in memory, and on a single node any restart empties them, graceful or not,
because there is no other node to hand them to. A declared ephemeral queue comes back configured.
In a cluster, a node that stops gracefully hands its ephemeral partitions to the others first
([ephemeral queues](/guides/ephemeral/)).

## Upgrade it

Stop the node with SIGTERM and start the new image on the same directory:

```bash
docker stop -t 60 queen && docker rm queen
docker run --platform linux/amd64 -d --name queen -p 6632:6632 -v queen-data:/var/lib/queen/raft \
  ghcr.io/queen-mq/queen:<new-version>
```

On SIGTERM the node stops accepting connections and lets the requests in flight finish. A parked
long-poll pop is one of them and can wait 30 seconds by default, so give the stop a minute. A
release never misreads data written by a newer one: a node whose directory belongs to a cluster
that writes a format above what the build reads refuses to start and says so (`run a release that
reads it ... never an older one`).

## Limits

One node is not highly available. While its process is down nothing is served, and its disk is the
only copy; for failover, run [three or five nodes](/operate/cluster/).

A single node started with the defaults does not grow into a cluster in place. It runs the local
replicator, and the cluster's replicator refuses a directory the local one wrote, so moving to a
cluster is a cutover: start the cluster beside the node, move the producers, let the consumers
drain the old node, then move them.

A 2.0 node does not read a 1.x PostgreSQL database, so coming from 1.x is the same cutover. The
broker's port is plain HTTP; TLS is on the proxy's listener or in front of the node
([security](/operate/security/)).

## The rest of this section

- [Run a cluster](/operate/cluster/): three or five nodes as one Raft cluster, starting from the
  tested Compose file in `deploy/compose/three-node/`, with quorum, failures and rolling upgrades.
- [Kubernetes](/operate/kubernetes/): the StatefulSet, its volumes, probes and upgrades.
- [Tenants, API keys and quotas](/operate/tenants/): the proxy inside the broker and its control
  plane.
- [Security](/operate/security/): which port serves what, authentication, the raft token, TLS and
  encryption at rest.
- [Monitoring](/operate/monitoring/): the dashboard, `/health`, the metrics and the log lines worth
  an alert.
- [Recovery](/operate/recovery/): what to do when a node, a disk or the majority is gone.

Source: https://queenmq.com/operate/index.mdx
