- Go 1.25+ (build from source) or Docker
- A Celestia node to index from:
- DA node (
celestia-node) -- full blob data + proof forwarding - Consensus node (
celestia-app) -- blob data via Cosmos SDK gRPC, no proof support
- DA node (
# From source
just build
# Binary at bin/apex
# Or with go install
go install github.com/evstack/apex/cmd/apex@latestGenerate a default config file:
apex init
# Creates config.yaml in the current directorydata_source:
type: "node"
celestia_node_url: "http://localhost:26658"
namespaces:
- "0000000000000000000000000000000000000000000000000000deadbeef"Set the auth token via environment variable (never in the config file):
export APEX_AUTH_TOKEN="your-celestia-node-auth-token"data_source:
type: "app"
celestia_app_grpc_addr: "localhost:9090"
namespaces:
- "0000000000000000000000000000000000000000000000000000deadbeef"No auth token needed for celestia-app. Proof endpoints (blob.GetProof, blob.Included) are unavailable in this mode.
data_source:
type: "node" # "node" or "app"
celestia_node_url: "http://localhost:26658" # required when type: node
celestia_app_grpc_addr: "localhost:9090" # required when type: app
namespaces: [] # hex-encoded, 29 bytes each
submission:
enabled: false # enable direct blob submission
app_grpc_addr: "localhost:9090" # celestia-app gRPC endpoint for submission
chain_id: "mocha-4" # chain ID used when signing transactions
signer_key: "/path/to/apex-submission.key" # file containing the hex-encoded secp256k1 key
storage:
db_path: "apex.db" # SQLite database path
rpc:
listen_addr: ":8080" # JSON-RPC + health
grpc_listen_addr: ":9090" # gRPC
read_timeout: 30 # HTTP read timeout in seconds
write_timeout: 30 # HTTP write timeout in seconds
sync:
start_height: 0 # 0 = genesis
batch_size: 256 # headers per backfill batch
concurrency: 12 # concurrent fetch workers
subscription:
buffer_size: 64 # event buffer per subscriber
max_subscribers: 1024 # maximum concurrent subscribers
metrics:
enabled: true
listen_addr: ":9091" # Prometheus /metrics
log:
level: "info" # trace/debug/info/warn/error/fatal/panic
format: "json" # json or consoleValidate a config without starting the server:
apex config validate --config config.yaml
apex config show --config config.yamlapex start
# Or with explicit path:
apex start --config /path/to/config.yamldocker build -t apex .
docker run -p 8080:8080 -p 9090:9090 -p 9091:9091 \
-e APEX_AUTH_TOKEN="your-token" \
-v $(pwd)/config.yaml:/config/config.yaml \
-v $(pwd)/data:/data \
apex --config /config/config.yamlThe image is based on distroless/static and runs as non-root (UID 65532).
just run startapex init Generate default config file
apex start --config config.yaml Start the indexer
apex status [--addr http://...] Check health endpoint
apex version Print version
apex config validate --config FILE Validate config
apex config show --config FILE Print resolved config
apex blob get HEIGHT NAMESPACE INDEX Get a single blob
apex blob list HEIGHT NAMESPACE List blobs at height
apex blob get-by-commitment HEX Get blob by commitment (no height needed)
All CLI data commands output JSON by default. Use --format table for human-readable output.
| Endpoint | Description |
|---|---|
GET /health |
Returns sync state, latest/network height, lag, version, uptime |
GET /health/ready |
Returns 200 when syncing or streaming, 503 otherwise |
Celestia-node compatible methods:
blob.Get,blob.GetAll,blob.GetByCommitment,blob.Subscribeblob.GetProof,blob.Included(DA node mode only, forwarded upstream)header.GetByHeight,header.LocalHead,header.NetworkHead,header.Subscribe
gRPC is Apex-owned and may evolve independently from the JSON-RPC compatibility layer. See API Compatibility Policy for the boundary.
apex.v1.BlobService: Get, GetAll, GetByCommitment, Subscribe (server-streaming)apex.v1.HeaderService: GetByHeight, LocalHead, NetworkHead, Subscribe (server-streaming)
When metrics.enabled: true, Prometheus metrics are served at http://localhost:9091/metrics. Metrics cover sync progress, API request counts, store query durations, and subscription health.