Skip to main content
Tessellation ships a complete Docker Compose setup that manages multi-node clusters (Global L0, DAG L1, and metagraph nodes) with automatic peer joining, health checks, and data persistence.

Docker Compose files

The docker/ directory contains layered Compose files:
FilePurpose
docker-compose.yamlCore services: gl0 (Global L0) and gl1 (DAG L1)
docker-compose.metagraph.yamlMetagraph services: ml0 (Currency L0), cl1, dl1 (Currency L1)
docker-compose.test.yamlTest network overlay — adds a shared bridge network for E2E tests
docker-compose.metagraph-test.yamlTest network overlay for metagraph services
docker-compose.volumes.yamlNamed Docker volumes for gl0-data and gl1-data
docker-compose.local-bridge.yamlLocal bridge network configuration
docker-compose.metagraph-genesis.yamlGenesis-mode configuration for metagraph bootstrap

Docker Compose profiles

Each service is gated behind a Compose profile, allowing selective startup:
ProfileServicePorts (public / p2p / cli)
l0gl0 — Global L09000 / 9001 / 9002
l1gl1 — DAG L19010 / 9011 / 9012
ml0ml0 — Currency L09020 / 9021 / 9022
cl1cl1 — Currency L19030 / 9031 / 9032
dl1dl1 — Data L19040 / 9041 / 9042

Quick start with just

1

Generate a keystore

java -jar keytool.jar generate \
  --keystore ./key.p12 \
  --alias alias \
  --password yourpassword
2

Start the environment

just up
To start against a specific published release instead of building locally:
just up --hypergraph-release=v3.5.11
3

Verify nodes are healthy

curl http://localhost:9000/node/health   # Global L0
curl http://localhost:9010/node/health   # DAG L1
4

Stop the environment

just down

The test suite

just test                    # Full: assemble JARs + start Docker + run all E2E tests
just test --skip-assembly    # Reuse existing JARs (faster iteration)
just test --test=dag-cluster # Run a specific test scenario
just test --list-tests       # Print all available test names
Available test scenarios:
just test --test=dag-cluster
just test --test=delegated-staking
just test --test=token-lock-replacement
just test --test=snapshot-streaming

Core service configuration

The Global L0 (gl0) and DAG L1 (gl1) services from docker-compose.yaml:
services:
  gl0:
    image: constellationnetwork/tessellation:${TESSELLATION_DOCKER_VERSION:-latest}
    container_name: gl0
    restart: unless-stopped
    env_file:
      - .env
    environment:
      - CL_DOCKER_ID=gl0
      - CL_KEYSTORE=/tessellation/key.p12
      - CL_PUBLIC_HTTP_PORT=9000
      - CL_P2P_HTTP_PORT=9001
      - CL_CLI_HTTP_PORT=9002
    ports:
      - "9000:9000"   # Public HTTP
      - "9001:9001"   # P2P HTTP
      - "9002:9002"   # CLI
    volumes:
      - ./key.p12:/tessellation/key.p12:ro
      - ./gl0-logs:/tessellation/logs
      - ./gl0-data:/tessellation/data
    healthcheck:
      test: ["CMD", "/tessellation/internal-health-check.sh"]
      interval: 3s
      timeout: 5s
      retries: 5
      start_period: 3s
    profiles: ["l0"]

Environment variables

Create a .env file in the project root (loaded by env_file: .env):
# Image version
TESSELLATION_DOCKER_VERSION=latest

# Keystore
CL_KEYSTORE_MOUNT_PATH=./key.p12
CL_PASSWORD=yourpassword

# Global L0 peer (for L1 nodes to connect to)
CL_DOCKER_GL0_PEER_HTTP_HOST=gl0
CL_DOCKER_GL0_PEER_HTTP_PORT=9000
CL_DOCKER_GL0_PEER_ID=<node-id-of-gl0>

# Genesis mode (first boot only)
CL_DOCKER_GL0_GENESIS=false

Volume mounts and data persistence

Each node container mounts three host paths:
MountContainer pathPurpose
./key.p12/tessellation/key.p12PKCS12 keystore (read-only)
./gl0-logs/tessellation/logsLog files
./gl0-data/tessellation/dataSnapshot data (persistent)
./seedlist/tessellation/seedlistPeer seedlist (optional)
./genesis.csv/tessellation/genesis.csvGenesis file (genesis mode only)
For named Docker volumes instead of host-path mounts, use docker-compose.volumes.yaml:
volumes:
  gl0-data:
    name: gl0-data
  gl1-data:
    name: gl1-data

Peer joining

The entrypoint.sh script handles automatic peer joining on container start. Key join parameters:
VariableDefaultDescription
CL_DOCKER_JOINtrueWhether to attempt joining
CL_DOCKER_JOIN_IPIP of the peer to join
CL_DOCKER_JOIN_PORT9001P2P port of the peer
CL_DOCKER_JOIN_IDNode ID of the peer
CL_DOCKER_JOIN_INITIAL_DELAY0 (L0) / 30 (L1)Seconds to wait before first join attempt
CL_DOCKER_JOIN_RETRIES10Number of join retries
CL_DOCKER_JOIN_DELAY10Seconds between retries
Joining is performed by POSTing to http://localhost:<cli-port>/cluster/join.

Multi-node setup

To run a complete metagraph stack (L0 + Currency L0 + Currency L1):
docker compose \
  -f docker/docker-compose.yaml \
  -f docker/docker-compose.metagraph.yaml \
  --profile l0 --profile l1 --profile ml0 --profile cl1 \
  up -d
Or use the just commands which manage profile selection automatically based on test requirements.

Build docs developers (and LLMs) love