Node Roles
The node ships with four logical roles. You select a role by settingNODE_ROLE in your environment. In production you can deploy each role as a separate container sharing the same PostgreSQL and Redis infrastructure.
api
HTTP ingress layer. Receives L2 transactions via REST, validates the CBOR envelope, and enqueues payloads to a Redis Stream for downstream processing.
tx-processor
Consumes the Redis Stream, deserializes each transaction, computes its hash, and inserts it into the mempool database. Scales horizontally — run multiple instances of this role against the same stream.
sequencer
Builds blocks from the mempool, commits block headers to the Cardano L1 state queue, and runs the L1 user-event sync fiber to pick up deposits and withdrawals.
all
Runs all three roles in a single process. This is the default and is recommended for getting started or running a single-node testnet setup.
Set
NODE_ROLE=all in your .env file to run everything in one container. Switch to the split Docker Compose profile to deploy api, tx-processor, and sequencer as separate services.Prerequisites
Before deploying the Sundial-Layer-Node, make sure you have the following ready:- Docker and Docker Compose (v2.20+)
- PostgreSQL 15 — the Docker Compose stack includes a bundled instance
- Redis 7+ — also bundled in the Docker Compose stack
- Cardano L1 provider — either a Blockfrost API key (quickest to set up) or a local Kupo + Ogmios endpoint pair (recommended for production)
- Operator seed phrases — three separate 24-word seed phrases for the main operator wallet, the block-commitment wallet, and the merge-transaction wallet
Quick Start with Docker Compose
The fastest way to run a node is with the bundled Docker Compose stack, which starts the node alongside PostgreSQL, Redis, and the full observability suite.1
Clone the repository
2
Create your environment file
Copy the example environment file and open it for editing:At minimum, set your L1 provider credentials and operator seed phrases. For a Blockfrost-backed testnet node:
3
Start all services
Launch the full stack (node + PostgreSQL + Redis + observability) using the To start only the node and its database dependencies without monitoring:
monolith profile:4
Verify the node is running
Confirm all containers started successfully:Then probe the node’s health and API endpoints:Follow the node logs in real time:
Smoke Checks
Run these checks after startup to confirm the full stack is healthy.1
Confirm the node is live and ready
2
Confirm Prometheus is scraping
prometheus, midgard_nodes, cadvisor, and tempo.3
Confirm metrics are flowing
Open Grafana at
http://localhost:3001 and verify the provisioned data sources — prometheus, Loki, and Tempo — are all shown as connected.Observability Stack
When you start the node with themonolith Docker Compose profile, the --with-monitoring flag is passed automatically. This activates the Prometheus metrics exporter on PROM_METRICS_PORT and the OpenTelemetry trace exporter pointed at Tempo.
The node exposes these tracked metrics:
Stopping and Cleaning Up
Split-Role Deployment
For production operators who want to scale transaction processing independently from block production, use thesplit Docker Compose profile. This starts node-api, node-tx-processor, and node-sequencer as separate containers, all sharing the same PostgreSQL and Redis backend.
NODE_ROLE from the environment override in the Compose file. You can run multiple node-tx-processor replicas to increase mempool ingestion throughput — they compete for work from the same Redis Stream consumer group.
Nix Deployment
If you prefer a reproducible Nix-based build, clone the standalone node repository and build from the tagged release:Troubleshooting
docker compose up fails with missing env values
docker compose up fails with missing env values
Verify that
demo/midgard-node/.env exists and all required variables are populated. Run grep -E '^(L1_PROVIDER|NETWORK|L1_OPERATOR_SEED_PHRASE)' .env to confirm the essentials are set.midgard_nodes Prometheus target is down
midgard_nodes Prometheus target is down
Confirm you started with the
monolith profile (not docker-compose.dev.yaml). Check that PROM_METRICS_PORT=9464 is set in your .env and that the node started with --with-monitoring in its command.No logs appearing in Loki
No logs appearing in Loki
Verify Promtail is running and has access to
/var/run/docker.sock and /var/lib/docker/containers. Confirm the node container has the logging: promtail label in the Compose file.No traces appearing in Tempo
No traces appearing in Tempo
Check that
OLTP_EXPORTER_URL=http://tempo:4318/v1/traces is set in your .env. The variable name is OLTP_EXPORTER_URL (not OTLP) — this is by design in the current implementation.Port conflicts on startup
Port conflicts on startup
The stack uses ports
3000, 3001, 3100, 3200, 4317, 4318, 5433, 6379, 8080, 9090, and 9464. Stop any existing services on those ports, or override them in .env using the _HOST_PORT variable variants.Loki fails to start repeatedly
Loki fails to start repeatedly
Run
docker compose down -v to clear the Loki volume, then restart with docker compose --profile monolith up -d --build.Hardware Requirements
For reliable block production on mainnet, run the node on hardware that meets or exceeds these specifications:
The AWS equivalent for the recommended configuration is an m6i.2xlarge instance (8 vCPU, 32 GB RAM).
Next Steps
Configuration Reference
Complete reference for all environment variables — L1 provider, timing intervals, PostgreSQL, Redis, and monitoring settings.
CLI Reference
Use the
midgard CLI to manage wallets, send transactions, and check node status from the command line.