# 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](/img/nodes/consensus-node.jpg)

## Minimum hardware requirements

See [hardware requirements](/operate/getting-started/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](/operate/getting-started/environment-setup).

### Install celestia-app

Follow the tutorial on [installing `celestia-app`](/operate/consensus-validators/install-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.

**Mainnet Beta**

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

**Mocha**

```bash
celestia-appd init "node-name" --chain-id mocha-5
```

Download the `genesis.json` file:

**Mainnet Beta**

```bash
celestia-appd download-genesis celestia
```

**Mocha**

```bash
celestia-appd download-genesis mocha-5
```

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

**Mainnet Beta**

```bash
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
```

**Mocha**

```bash
SEEDS=$(curl -sL https://raw.githubusercontent.com/celestiaorg/networks/main/mocha-5/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 set persistent peers in your `config.toml` file. If you set persistent peers, your node will **always** try to connect to these peers. This is useful when running a local devnet, for example, when you would always want to connect to the same local nodes in your devnet. In production, setting persistent peers is advised only if you are running a [sentry node](https://hub.cosmos.network/main/validators/security.html#sentry-nodes-ddos-protection).

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

**Mainnet Beta**

```bash
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
```

**Mocha**

```bash
PERSISTENT_PEERS=$(curl -sL https://raw.githubusercontent.com/celestiaorg/networks/main/mocha-5/peers.txt | tr '\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](https://github.com/celestiaorg/celestia-app/tree/v9.x/tools/migrate-db)
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`:

```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.

```toml
# 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`:

```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:

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

`min-retain-blocks` defaults to `0`. Any non-zero value enables block pruning,
so archival operators must keep the value at `0`. Changing the value from `0`
to a non-zero value starts pruning the existing backlog when the node restarts
and can temporarily increase sync time.

### 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:

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

### Recommended block retention for validators

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:

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

## Sync types

| Sync mode  | Time     | Notes                                                                                                                                        |
| ---------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Block sync | ~3 weeks | Downloads and executes all blocks from genesis to the tip                                                                                    |
| State sync | ~1 hour  | Downloads a snapshot of the state then downloads and executes all blocks after that snapshot to the tip.                                     |
| Quick sync | ~5 hours | Downloads 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:

```toml
[blocksync]
verify_data = true
```

See the [celestia-app v9 release notes](https://github.com/celestiaorg/celestia-app/blob/v9.0.4/docs/release-notes/release-notes.md#block-sync-verify_data-default-changed-to-false)
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](https://github.com/cosmos/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](/operate/networks/overview):**

> **Note:** State sync scripts for each network are available in the [networks repository](https://github.com/celestiaorg/networks).

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

```toml
rpc_servers = ""
trust_height = 0
trust_hash = ""
```

And also set statesync to `true`:

```toml
#######################################################
###         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:

**Mainnet Beta**

```bash
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/
```

**Mocha**

```bash
cd $HOME
rm -rf ~/.celestia-app/data
mkdir -p ~/.celestia-app/data
SNAP_NAME=$(curl -s https://snaps.qubelabs.io/celestia/ | \
    egrep -o ">mocha-5.*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/
```

The [Node snapshots guide](/operate/maintenance/snapshots) provides everything you need to quick sync your node:

- Details about pruned and archive snapshots
- A list of snapshot providers for different node types
- Installation and usage instructions for `celestia-snapshot-finder` - a tool that automatically finds and downloads the fastest snapshot for your server location

## 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`.

```sh
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.

**Mainnet Beta**

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

**Mocha**

```sh
celestia-appd start --v2-upgrade-height 2585031
```

Optional: If you would like celestia-app to run as a background process, you can follow the [SystemD tutorial](/operate/maintenance/systemd).

## 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:

```sh
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:

```sh
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.

#### Option 3: Manual reset (recommended for validator nodes)

For more granular control over what gets reset:

```sh
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:

```sh
# 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.

If you're running a bridge node that connects to your consensus node, ensure that gRPC is properly configured in your `app.toml` file. Bridge nodes require gRPC access (typically on port 9090) to communicate with the consensus layer.

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`:

```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`:

```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](https://github.com/celestiaorg/celestia-core/pull/3329),
released in the v0.40 line in
[v0.40.11](https://github.com/celestiaorg/celestia-core/releases/tag/v0.40.11)
and in the v0.42 line in
[v0.42.2](https://github.com/celestiaorg/celestia-core/releases/tag/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](/operate/networks/overview).

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](https://github.com/celestiaorg/celestia-core/releases/tag/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:

```sh
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.

```sh
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:

```toml
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:

```toml
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.

```diff
# 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

```sh
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:

```sh
celestia-appd passthrough v1 query bank balances [address]
```

Query validator information using app version 2 format:

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

Query transaction using app version 3 format:

```sh
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:

```sh
celestia-appd passthrough --help
```

To see available commands for a specific app version:

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