> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firebolt.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Colocate multiple nodes on one host

> Run several Firebolt nodes or Engines on a single machine for local testing, avoiding the port collisions that a one-node-per-machine layout never hits.

<Warning>
  This is for local testing only, for example a database engineer testing distributed execution on a laptop.
  A production deployment runs [one node per machine](./overview#concepts), where the default ports never collide and none of this applies.
  Do not colocate nodes to save machines in production.
</Warning>

When two nodes share a host they cannot both use the same ports, and two Engine leaders cannot both claim the storage manager's fixed port on the same address.
This page covers the two cases that need that extra care: a multi-node Engine on one host, and two Engines on one host.

## Use 127.0.0.1, not localhost

On a single machine, set every `host` to `127.0.0.1`, not `localhost`.
`localhost` resolves to both `::1` and `127.0.0.1`, and the node-to-node gRPC channels flap between the two address families and drop mid-query.

## A multi-node engine on one host

This is the [multi-node embedded-metadata Engine](./embedded-metadata#multi-node-engine), with both nodes on one machine.
Because the two processes share a host, give every node-to-node port a distinct value so they do not collide.
Leave `storage_manager_port` at its default: only node 0, the leader, binds it.

```bash theme={"theme":{"light":"css-variables","dark":"css-variables"}}
mkdir -p node0 node1
cat > node0/config.yaml <<'EOF'
schema_version: "1.0"
engine:
  nodes:
    - host: 127.0.0.1          # node 0 hosts embedded metadata on :6500
      aragog_port: 5678
      shufflepuff_port: 16000
      storage_agent_port: 3434
      health_check_port: 8122
      prometheus_port: 9090
    - host: 127.0.0.1          # node 1, every port distinct from node 0
      aragog_port: 5679
      shufflepuff_port: 16001
      storage_agent_port: 3435
      health_check_port: 8123
      prometheus_port: 9091
storage:
  type: s3
  bucket_name: my-firebolt-bucket
  aws:
    region: us-east-1
EOF
cp node0/config.yaml node1/config.yaml
```

Start both nodes concurrently, then wait for both to report ready.
Do not use `--detach`: each node's readiness check needs its peer, so starting them one at a time deadlocks.

```bash theme={"theme":{"light":"css-variables","dark":"css-variables"}}
firebolt server start --data-dir "$PWD/node0" --node 0 --http-port 3473 &
NODE0_PID=$!
firebolt server start --data-dir "$PWD/node1" --node 1 --http-port 3474 &
NODE1_PID=$!

until curl -sf localhost:3473/ping >/dev/null && curl -sf localhost:3474/ping >/dev/null; do sleep 2; done
echo "both ready (node0=$NODE0_PID node1=$NODE1_PID)"
```

Nothing needs to be reachable from outside the machine except the `--http-port` of the node you send queries to.

The same approach works with standalone metadata: configure the nodes as in [Deploy with standalone metadata](./standalone-metadata#one-multi-node-engine), give each node distinct ports as above, and run `dedicated-pensieve` alongside them on the same host.

## Two engines on one host

This is [Multiple engines](./standalone-metadata#multiple-engines), with both Engines on one machine.
Distinct per-node ports are not enough here, because the storage manager runs on a fixed port, 1717, on each Engine's leader node.
By default an Engine binds every listener on all interfaces (`0.0.0.0`), so two leaders on one host would both try to claim `0.0.0.0:1717` and the second fails to start.

Set `engine.listen_host` to give each Engine a distinct bind address and the collision goes away: each leader binds `1717` on its own address.
On Linux every address in `127.0.0.0/8` is loopback with no setup, so two loopback aliases are the simplest choice.
Bind Engine A to `127.0.0.1` and Engine B to `127.0.0.2`, set each Engine's `nodes[].host` to its own bind address, and point both at the same metadata service and bucket:

```yaml theme={"theme":{"light":"css-variables","dark":"css-variables"}}
# Engine A, colocated
schema_version: "1.0"
instance:
  type: multi_engine
  multi_engine:
    metadata_endpoint: 127.0.0.1:7000
engine:
  id: engine-a
  listen_host: 127.0.0.1          # bind this Engine's listeners here
  nodes:
    - host: 127.0.0.1
      aragog_port: 5678
      shufflepuff_port: 16000
      storage_agent_port: 3434
      health_check_port: 8122
      prometheus_port: 9090
    - host: 127.0.0.1
      aragog_port: 5679
      shufflepuff_port: 16001
      storage_agent_port: 3435
      health_check_port: 8123
      prometheus_port: 9091
storage:
  type: s3
  bucket_name: my-firebolt-bucket
  aws:
    region: us-east-1
```

Engine B's config is identical except for three values: `id: engine-b`, `listen_host: 127.0.0.2`, and both `nodes[].host` set to `127.0.0.2`.
Because the two Engines bind different addresses, Engine B reuses Engine A's port numbers unchanged.

`listen_host` must be an address that the same Engine's `nodes[].host` entries resolve to, since each node both binds and advertises that address.
Leave `listen_host` unset (the default) whenever an Engine has a machine to itself: it then binds `0.0.0.0` and is reachable on every interface.

A single-node Engine is its own leader and has no peer depending on the leader's port, so several single-node Engines colocate on one host without setting `listen_host` at all.
