Skip to main content
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, where the default ports never collide and none of this applies. Do not colocate nodes to save machines in production.
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, 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.
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.
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, 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, 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:
# 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.