Skip to content
LogoLogo

Consensus node

This guide covers how to set up a consensus node on Celestia. Consensus nodes allow you to sync the entire blockchain history in the Celestia consensus layer.

consensus node

Minimum hardware requirements

See hardware requirements.

Set up a consensus node

The following tutorial is done on an Ubuntu Linux 24.04 (LTS) x64 instance machine.

Set up the dependencies

Follow the instructions on installing dependencies.

Install celestia-app

Follow the tutorial on installing celestia-app.

Set up the P2P networks

To initialize the network, pick a "node-name" that describes your node. Keep in mind that this might change if a new testnet is deployed.

celestia-appd init "node-name" --chain-id celestia

Download the genesis.json file:

celestia-appd download-genesis celestia

Set seeds in the $HOME/.celestia-app/config/config.toml file:

SEEDS=$(curl -sL https://raw.githubusercontent.com/celestiaorg/networks/master/celestia/seeds.txt | tr '\n' ',')
echo $SEEDS
sed -i.bak -e "s/^seeds *=.*/seeds = \"$SEEDS\"/" $HOME/.celestia-app/config/config.toml

Optional: Set persistent peers

You can get the persistent peers from the @cosmos/chain-registry repository (for Mainnet Beta) or @celestiaorg/networks repository repo (for Mocha) with the following commands:

PERSISTENT_PEERS=$(curl -s https://raw.githubusercontent.com/cosmos/chain-registry/master/celestia/chain.json | jq -r '.peers.persistent_peers[].address' | tr '\n' ',' | sed 's/,$/\n/')
echo $PERSISTENT_PEERS
sed -i.bak -e "s/^persistent_peers *=.*/persistent_peers = \"$PERSISTENT_PEERS\"/" $HOME/.celestia-app/config/config.toml

Storage and pruning configurations

Database backend

celestia-app v9 and later use PebbleDB by default for new nodes. Before changing an existing node's db_backend from "goleveldb" to "pebbledb", stop the node and use the migrate-db tool to migrate its databases.

Optional: Connect a consensus node to a bridge node

If your consensus node is being connected to a celestia-node bridge node, configure indexing in config.toml and block retention in app.toml as described below. The consensus node does not need to retain the full block history for either a pruned or an archival bridge node.

Enable transaction indexing

There is currently no way of entirely disabling indexing. Set the indexer to "null" in your config.toml:

indexer = "null"

The null indexer is a lightweight indexer that is sufficient for bridge nodes.

Retain blocks for bridge nodes

Keep blocks that fall inside the bridge storage window (169h). The bridge node's live listener fetches newly announced blocks from this consensus node. During header sync, recent ranges come from consensus and older ranges come from the header peer exchange. The data availability sampler retrieves share data from DA peers. Peers may not retain a complete history.

min-retain-blocks in app.toml is a block count, not a duration. Cover the storage window at the network's block rate. On Mainnet Beta, a 3-second target is 202,800 blocks over 169 hours, and the documented 2.6-second happy-path cadence is 234,000 blocks. Use at least the count for the faster rate, increase it if blocks are produced faster, and recalculate when another network uses a different block time. A value of 0 retains every block. Neither a pruned nor an archival bridge node requires that.

# Mainnet Beta: 169 hours at a 2.6-second block time.
# Increase this if blocks are produced faster, and recalculate for a different block time.
# 0 keeps the entire chain and is not required.
min-retain-blocks = 234000

Query transactions by hash

To query transactions using their hash, transaction indexing must be turned on. Set the indexer to "kv" in your config.toml:

indexer = "kv"

Optional: Access historical state

If you want to query the historical state — for example, you might want to know the balance of a Celestia wallet at a given height in the past — you should run an archive node. In your app.toml, set pruning = "nothing" to retain application state and min-retain-blocks = 0 to retain all block data. Note that this configuration is resource-intensive and will require significant storage:

pruning = "nothing"
min-retain-blocks = 0

Save on storage requirements

If you want to save on storage requirements, consider using pruning = "everything" in your app.toml to prune everything. If you select "everything" or "default", but still want to keep the block data, you can do so by explicitly setting min-retain-blocks = 0 in your app.toml. A value of 0 for min-retain-blocks will keep all block data. This will prune snapshots of the state, but it will keep block data:

pruning = "everything"
min-retain-blocks = 0 # retain all block data

The default min-retain-blocks value is 3000. For validators that do not need to retain all block data, set min-retain-blocks = 600000 in your app.toml. This keeps a larger recent block history without retaining all block data:

min-retain-blocks = 600000 # retain recent block data while pruning older blocks

Sync types

Sync modeTimeNotes
Block sync~3 weeksDownloads and executes all blocks from genesis to the tip
State sync~1 hourDownloads a snapshot of the state then downloads and executes all blocks after that snapshot to the tip.
Quick sync~5 hoursDownloads the data directory from a node. Time depends on your download speed because the data being downloaded can exceed 1 TB for mainnet.

Option 1: Block sync

By default, a consensus node will sync using block sync; which will request, validate and execute every block up to the head of the blockchain. This is the most secure mechanism yet the slowest (taking up to weeks depending on the height of the blockchain).

Starting with celestia-app v9, verify_data defaults to false in the [blocksync] section of config.toml. This skips re-running ProcessProposal on historical blocks to improve block sync speed. Blocks are still verified by their validator signatures, and normal validation resumes after the node enters consensus mode. To restore the pre-v9 behaviour, set:

[blocksync]
verify_data = true

See the celestia-app v9 release notes for details.

There are two alternatives for quicker syncing.

Option 2: State sync

State sync uses light client verification to verify state snapshots from peers and then apply them. State sync relies on weak subjectivity; a trusted header (specifically the hash and height) must be provided. This can be found by querying a trusted RPC endpoint (/block). RPC endpoints are also required for retrieving light blocks. These can be found in the docs here under the respective networks or from the chain-registry.

State sync quick start scripts

If you are looking to quickly sync a consensus node, and do not need historical blocks, you can use the following scripts and state sync.

Before running the scripts, make sure to checkout to the correct version:

Note: State sync scripts for each network are available in the networks repository.

The public networks will use state sync so they'll get to the tip very quickly, but won't work for your use case if you need historical blocks.

Manual state sync setup

In $HOME/.celestia-app/config/config.toml, set

rpc_servers = ""
trust_height = 0
trust_hash = ""

And also set statesync to true:

#######################################################
###         State Sync Configuration Options        ###
#######################################################
[statesync]
enable = true

To their respective fields. At least two different rpc endpoints should be provided. The more, the greater the chance of detecting any fraudulent behavior.

Once setup, you should be ready to start the node as normal. In the logs, you should see: Discovering snapshots. This may take a few minutes before snapshots are found depending on the network topology.

Option 3: Quick sync

Quick sync effectively downloads the entire data directory from a third-party provider meaning the node has all the application and blockchain state as the node it was copied from.

Run the following command to quick-sync from a snapshot:

cd $HOME
rm -rf ~/.celestia-app/data
mkdir -p ~/.celestia-app/data
SNAP_NAME=$(curl -s https://snaps.qubelabs.io/celestia/ | \
    egrep -o ">celestia.*tar" | tr -d ">")
aria2c -x 16 -s 16 -o celestia-snap.tar "https://snaps.qubelabs.io/celestia/${SNAP_NAME}"
tar xf celestia-snap.tar -C ~/.celestia-app/data/

Start the consensus node

If you are running celestia-app >= v4.0.0, the rpc.grpc_laddr config option is required. This option can be set via the CLI flag --rpc.grpc_laddr tcp://0.0.0.0:9098 or in the config.toml.

celestia-appd start --rpc.grpc_laddr tcp://0.0.0.0:9098

If you are running celestia-app v2.x.x then you'll want to start the node with a --v2-upgrade-height that is dependent on the network. The --v2-upgrade-height flag is only needed during the v2 upgrade height so after your node has executed the upgrade (e.g. you see the log upgraded from app version 1 to 2), you don't need to provide this flag for future celestia-appd start invocations.

celestia-appd start --v2-upgrade-height 2371495

Optional: If you would like celestia-app to run as a background process, you can follow the SystemD tutorial.

Extra resources for consensus nodes

Optional: Reset network

There are several ways to reset your consensus node, depending on what you need to preserve:

Option 1: Reset blockchain data with reset-state

This command removes blockchain data but preserves validator state and address book of the consensus node:

celestia-appd tendermint reset-state

This preserves your configuration, validator state (priv_validator_state.json), and peer connections (addrbook.json), but removes:

  • blockstore.db
  • state.db
  • evidence.db

This option is safe for validator nodes and was created specifically for validators who need to reset their node's blockchain data without risking double signing. Use this when you need to resync your node but want to maintain your validator's signing state and peer connections.

Option 2: Full reset with unsafe-reset-all

⚠️ CAUTION FOR VALIDATORS: This is considered "unsafe" because it resets validator state:

celestia-appd tendermint unsafe-reset-all --home $HOME/.celestia-app

This command:

  • Resets blockchain data
  • Resets validator state (priv_validator_state.json) but NOT private keys (which are in priv_validator_key.json)
  • Clears address book (addrbook.json)
  • Preserves node configuration

This option should ONLY be used when you're absolutely certain your validator isn't actively participating in consensus. Using this while your validator is active could lead to double signing. Always back up your validator keys before using this command.

For more granular control over what gets reset:

mv ~/.celestia-app/data ~/.celestia-app/old-data
mkdir -pv ~/.celestia-app/data
cp ~/.celestia-app/old-data/priv_validator_state.json ~/.celestia-app/data/priv_validator_state.json

This approach lets you manually preserve the validator state file while replacing all other data. The advantage over Option 1 is that you can selectively copy additional files if needed. Use this when you want maximum control over which files are preserved during reset.

Option 4: Simple data directory cleanup

For non-validator nodes, you can completely erase all blockchain data and test keys by removing and recreating the data directory:

# Remove data directory
rm -rf ~/.celestia-app/data
rm -rf ~/.celestia-app/keyring-test
 
# Create data directory and initialize validator state file
mkdir -p ~/.celestia-app/data/
echo "{}" > ~/.celestia-app/data/priv_validator_state.json

This approach:

  • Completely removes all blockchain data (blocks, state, evidence, etc.)
  • Removes the keyring-test directory containing transaction signing keys (but not validator consensus keys)
  • Creates a new, empty data directory structure
  • Initializes a blank validator state file, which erases the record of blocks your validator has signed

Important: This option should NOT be used for validator nodes because it creates a double-signing risk. The validator's consensus private key (in priv_validator_key.json in the config directory) remains intact, but the node loses all record of which blocks it has already signed. If the node is still an active validator on the network, it could sign conflicting blocks at the same height, resulting in slashing penalties.

Use this option only for non-validator nodes when you want a complete fresh start with no preserved state or connections.

It's recommended to test these commands on a testnet first before applying them to a mainnet node.

Optional: Configure an RPC endpoint

You can configure your consensus node to be a public RPC endpoint. This allows it to accept connections from data availability nodes and serve requests for the data availability API.

The Cosmos SDK REST API also requires application gRPC. If you enable [api] with enable = true in config/app.toml, keep enable = true in the existing [grpc] section. The equivalent CLI flags are --api.enable=true --grpc.enable=true. The rpc.grpc_laddr setting in config.toml configures a separate service and does not satisfy this dependency.

Configure heavy RPC concurrency

Memory-intensive RPC endpoints share a process-wide concurrency limit across HTTP, WebSocket and gRPC. The default limit is 20 concurrent requests. Set it under [rpc] in config.toml:

[rpc]
max_concurrent_heavy_requests = 20

A value of 0 selects the built-in default of 20. A negative value disables the limit, which is not recommended. Increasing the limit can increase peak memory consumption. Only raise it when the node has sufficient RAM, and monitor node memory usage under RPC load.

With celestia-core v0.42.3, genesis and genesis_chunked also share this budget. celestia-app has included that core since v10.4.0 and v10.4.0-mocha, including the current v10.5.0 and v10.5.0-mocha releases. The multiplexer uses that core even while it serves an earlier application version.

When the budget is full, HTTP URI requests return 503. JSON-RPC and WebSocket requests return an error with server busy: too many concurrent heavy RPC requests, retry later in error.data. gRPC heavy methods return status ResourceExhausted with the same message. Reduce concurrent requests and retry with backoff.

Configure RPC search limits

For nodes using the kv indexer, max_search_results limits how many matches a tx_search or block_search query can accumulate in memory before pagination. The default is 100000. To configure it, edit the existing [tx_index] section in $HOME/.celestia-app/config/config.toml:

[tx_index]
indexer = "kv"
max_search_results = 100000

Restart celestia-appd after changing the setting. A value of 0 or a negative value removes the cap, allowing broad searches to consume more memory. This setting applies to the key-value indexer, not the PostgreSQL indexer.

If a query exceeds the cap, it fails with search query too broad: narrow the query instead of returning a truncated page. Narrow the query, for example by searching a smaller height range. Reducing per_page or requesting a different page does not avoid the cap because matching happens before pagination.

This setting requires a celestia-app binary that includes the search cap from celestia-core #3329, released in the v0.40 line in v0.40.11 and in the v0.42 line in v0.42.2. For example, celestia-app v9.0.8 uses celestia-core v0.40.9 and does not support this setting. v10.4.0, v10.4.0-mocha, and later releases that include celestia-core v0.42.3 do, including the current v10.5.0 and v10.5.0-mocha binaries. Check the celestia-core dependency in your celestia-app release's go.mod before configuring it, and use the release for your network.

Both methods also reject query strings longer than 512 bytes with maximum query length exceeded. This limit is fixed, not a configuration setting. Shorten the query before retrying.

tx_search already enforced this query-length limit; celestia-core v0.42.3 extended it to block_search. These protections follow the binary, starting with celestia-app v10.4.0 and v10.4.0-mocha, and do not wait for app version 10 to activate on the network.

Expose RPC

By default, the RPC service listens on localhost which means it can't be accessed from other machines. To make the RPC service available publicly, you need to bind it to a public IP or 0.0.0.0 (which means listening on all available network interfaces).

You can do this by editing the config.toml file:

sed -i 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' ~/.celestia-app/config/config.toml

This command replaces the localhost IP address with 0.0.0.0, making the RPC service listen on all available network interfaces.

Note on external-address

The external-address field in the configuration is used when your node is behind a NAT and you need to advertise a different address for peers to dial. Populating this field is not necessary for making the RPC endpoint public.

EXTERNAL-ADDRESS=$(wget -qO- eth0.me)
sed -i.bak -e "s/^external-address = ""/external-address = "$EXTERNAL-ADDRESS:26656"/" \
    $HOME/.celestia-app/config/config.toml

Restart the node

After making these changes, restart celestia-appd to load the new configurations.

Optional: Transaction indexer configuration options

This section guides you on how to configure your config.toml file in celestia-app to select which transactions to index. Depending on the application's configuration, a node operator may decide which transactions to index.

The available options are:

  1. null (default): This option disables indexing outside of transaction status. If you don't need to query transaction data, you can choose this option to save space.
  2. kv: This is the simplest indexer, backed by PebbleDB key-value storage. When kv is chosen, tx.height and tx.hash will always be indexed. This option is suitable for basic queries on transactions.
  3. psql: This indexer is backed by PostgreSQL. When psql is chosen, tx.height and tx.hash will always be indexed. This option is suitable for complex queries on transactions.

An example to set the value to kv in config.toml is:

indexer = "kv"

Remember to restart celestia-appd after making changes to the configuration to load the new settings.

Optional: Discard ABCI responses configuration

This section will guide you on how to configure your config.toml file in celestia-app to manage the storage of ABCI responses. ABCI responses are the results of executing transactions and are used for /block_results RPC queries and to reindex events in the command-line tool.

The discard_abci_responses option allows you to control whether these responses are persisted in the state store:

  • false (default): ABCI responses are stored in the state store. This ensures that ABCI responses are available for /block_results RPC queries and for reindexing events. However, it can consume a significant amount of disk space.
  • true: ABCI responses are not stored in the state store. This can save a considerable amount of disk space, but /block_results RPC queries and event reindexing will not be available.

An example to set the value to false in config.toml is:

discard_abci_responses = false

Remember to restart celestia-appd after making changes to the configuration to load the new settings.

Optional: Reduce log level

To reduce the log level, you can modify the log_level field in your config.toml file.

# Output level for logging, including package level options
-log_level = "info"
+log_level = "*:error,p2p:info,state:info"

Passthrough command for historical queries

Starting with celestia-app v4 the passthrough command allows you to invoke queries on historical app versions. This is particularly useful when you need to query data from before a major version upgrade occurred.

When to use the passthrough command

The passthrough command is useful in scenarios where:

  • You need to query state or transactions that existed before a major app version upgrade
  • You're running a post-upgrade node but need to access data using the query format from a previous version
  • You're debugging issues related to version compatibility after an upgrade

Basic usage

celestia-appd passthrough [app-version] [command] [flags]

Where:

  • [app-version] is the historical app version you want to query against (e.g., v1, v2, v3)
  • [command] is the command you want to execute using that app version's format

Examples

Query account balance using app version 1 format:

celestia-appd passthrough v1 query bank balances [address]

Query validator information using app version 2 format:

celestia-appd passthrough v2 query staking validator [validator-address]

Query transaction using app version 3 format:

celestia-appd passthrough v3 query tx [transaction-hash]

Important considerations

  • The passthrough command requires that your node has the historical data for the version you're querying
  • Not all query types may be available for all historical versions
  • This command is most useful immediately after major version upgrades when you need backward compatibility
  • Ensure your node is fully synced before using passthrough queries for accurate results

Getting help

To see all available options for the passthrough command:

celestia-appd passthrough --help

To see available commands for a specific app version:

celestia-appd passthrough [app-version] --help