Run a split validator node
Running split validators for Arbitrum chains
Split validators separate the validation work to a stateless validation node, which provides several key benefits:
- Resource management: Easier to scale and manage compute resources independently
- Fault isolation: Prevents database corruption if the validation node crashes (e.g., due to OOM errors)
- Flexibility: Allows running multiple validation nodes for horizontal scalability
This guide explains how to set up a split validator configuration for Arbitrum chains by running a Nitro node (bonder) and a validation node separately.
Before you read this doc, please ensure you have already walked through run a validator docs to understand the basics of a validator node.
What is AUTH-RPC and the validation API
Nitro nodes can expose two separate WebSocket RPC interfaces:
- The public RPC (configured under
--http.*and--ws.*) serves the standardeth_,net_, and other namespaces that wallets and dApps use. - AUTH-RPC (configured under
--auth.*) is a second, JWT-authenticated WebSocket interface intended for trusted intra-component communication. It listens on its own address and port and by default exposes only thevalidationnamespace.
The validation_* namespace is how the bonder delegates WASM execution to the validation node—it carries Validate (run the WASM machine on a prepared input and return the resulting global state) plus CreateExecutionRun, GetStepAt, and GetProofAt (used during challenges to fetch step hashes and one-step proofs). The full method list is in the validation_* API reference below.
The rest of this guide walks through the deployment; the API reference and the option to expose additional namespaces over AUTH-RPC are at the end.
Prerequisites
- Docker or Kubernetes with Helm installed
- Bonder private key
- Chain information JSON for your Arbitrum chain
Docker deployment guide
Step 1: Set up the validation node
First, generate a JWT secret for secure communication:
xxd -l 32 -ps -c 40 /dev/urandom > /tmp/nitro-val.jwt
Start the validation node with the JWT secret:
docker run --rm -it \
--entrypoint nitro-val \
-p 0.0.0.0:5200:5200 \
offchainlabs/nitro-node:v3.9.9-6b0af88 \
--auth.addr 127.0.0.1 \
--auth.origins 0.0.0.0 \
--auth.jwtsecret /tmp/nitro-val.jwt \
--auth.port 5200
--metrics \
--metrics-server.addr=0.0.0.0 \
--metrics-server.port=6070
The validation node will listen on port 5200, which will also enable the metrics server on port 6070.
Step 2: Set up the bonder node
Copy the JWT secret to your mount directory:
cp /tmp/nitro-val.jwt /some/local/dir/arbitrum
Start the bonder node with the following command, connecting it to your validation node:
docker run --rm -it \
-v /some/local/dir/arbitrum:/home/user/.arbitrum \
offchainlabs/nitro-node:v3.9.9-6b0af88 \
--parent-chain.connection.url=<parent-chain-endpoint> \
--node.staker.enable=true \
--node.staker.strategy=MakeNodes \
--node.staker.parent-chain-wallet.private-key=<staker_private_key> \
--chain.info-json=<Your_chain_info> \
--execution.forwarding-target=<forwarding_target> \
--node.block-validator.validation-server-configs-list="[{\"jwtsecret\":\"/home/user/.arbitrum/nitro-val.jwt\",\"url\":\"ws://Your_validation_address\"}]"
Replace the placeholders with your specific values:
<parent-chain-endpoint>: Your parent chain RPC endpoint<staker_private_key>: Your bonder's private key<Your_chain_info>: Chain information JSON<forwarding_target>: Your forwarding node URL (usually is the sequencer endpoint)Your_validation_address: Address of your validation node (including port)
Kubernetes deployment with Helm
Arbitrum provides a community Helm chart for Kubernetes deployment.
Step 1: Create validation node configuration
Create a file named validation_values.yaml:
configmap:
data:
parent-chain:
id: 1 # Use appropriate parent chain ID
connection:
url: 'https://your-parent-chain-rpc'
execution:
forwarding-target: 'https://your-forwarding-node'
node:
staker:
enable: true
strategy: 'MakeNodes'
parent-chain-wallet:
private-key: 'your-staker-private-key'
chain:
name: 'Your Chain Name'
id: 42161 # Your chain ID
info-json: '[Your chain info JSON]'
jwtSecret:
enabled: true
value: 'Your 32 bytes hex jwt'
validator:
enabled: true
splitvalidator:
deployments:
- name: 'current'
Step 2: Deploy the validation node
helm install nitro-validator offchainlabs/nitro --values validation_values.yaml
Monitoring and maintenance
-
Monitor your bonding and validation node logs regularly:
# For Dockerdocker logs -f <container_id># For Kuberneteskubectl logs -f <POD> -
Check the status of both the bond and the validation node through the Arbitrum dashboard or API
Additional configurations for validation nodes
To get a full list of parameters for the validation node, you can run the following command:
docker run --rm -it --entrypoint nitro-val offchainlabs/nitro-node:v3.9.9-6b0af88 --help
Additional configurations for helm charts
For more advanced helm chart configurations, please refer to the Arbitrum community Helm Chart README
Monitoring
To check if your validation node is running correctly, you can check the rpc_duration_validation_validate_success_count metric in your metrics server.
This metric is a counter of the number of successful validation calls; if it is increasing, it means your validation node is running correctly.
You can also check where this log (validation node started) appears:
-
If this log appears on the validation node, it means your validation node is running correctly.
-
If this log appears on the bond node, it means your bond node is still validating itself. It indicates that your bond node is not connecting to the validation node correctly; you need to double-check your configuration.
Reference: the validation_* API
When AUTH-RPC is enabled, the validation node registers the validation namespace, exposing the following methods (all prefixed validation_ in RPC requests):
| Method | Purpose |
|---|---|
validation_name | Returns the validation node identifier. |
validation_capacity | Returns the configured concurrent-execution capacity. |
validation_room | Returns the number of currently available execution slots. |
validation_validate | Runs one validation against a given input and WASM module root. |
validation_wasmModuleRoots | Lists the WASM module roots this node can validate. |
validation_stylusArchs | Lists the Stylus target architectures the node supports. |
validation_createExecutionRun | Starts a long-running execution and returns an execid handle. |
validation_getStepAt | Returns the machine hash and global state at a given step. |
validation_getMachineHashesWithStepSize | Batch step-hash lookup, used during challenge resolution. |
validation_getProofAt | Returns the one-step proof at a given step. |
validation_prepareRange | Pre-loads execution state for a step range. |
validation_execKeepAlive | Heartbeats an execution run to extend its retention. |
validation_checkAlive | Probes that an execution run is still loaded on the validation node. |
validation_closeExec | Releases an execution run's resources. |
These methods are internal protocol calls between the bond and the validation node. You normally don't invoke them directly—the bonder calls them automatically when it needs validation work. This reference is most useful for reading logs or debugging connectivity between the two components.
Advanced: exposing additional namespaces over AUTH-RPC
--auth.api accepts a list of namespaces, not just validation. You can add others—for example, eth or net — if you want to grant a trusted client read access to those APIs without exposing them on the public RPC:
--auth.api validation,eth,net
Anything listed here is served on the AUTH-RPC endpoint and gated by the JWT, so the caller must hold the same JWT secret to access it. The endpoint still listens only on --auth.addr (default 127.0.0.1), so keep it on loopback or a private network — JWT authentication alone is not a substitute for network isolation.
This is rarely needed for bonders; the main use case is internal services (a custom monitor, an indexer behind your own bastion) that need authenticated read access to the node.
- If this log appears on the bonder node (validator node), it means your bonder node is still validating itself. It indicates that your bonder node is not connecting to the validation node correctly; you need to double-check your configuration.