How to Run Your Own Arbitrum Full Node

An Arbitrum One node runs the Nitrostack — Geth-derived execution plus rollup consensus — and gives you a private RPC on chain ID 42161with no rate limits and blocks every ~250 ms. The honest headline numbers before you start: a full node’s state is about 2.3–2.4 TB of NVMe, you need an Ethereum L1 endpoint and a beacon endpoint (Nitro reads blob data), and initial setup means downloading a snapshot measured in terabytes. This guide follows the official Offchain Labs process with the current offchainlabs/nitro-node:v3.11.3 image.

Hardware requirements

ResourceFull nodeArchive node
Disk (NVMe, strongly preferred)~2.3 TB HashDB pruned snapshot (~2.4 TB PathDB full-path)~3.7 TB PathDB archive-path snapshot (HashDB archive is considerably larger)
RAMThe official memory example targets a 64 GB machine (GOMEMLIMIT=48GiB) — budget accordinglySame or more; PathDB builds a state-history index
CPUModern multi-core (Nitro is Go + WASM-heavy)Same
External endpointsEthereum L1 RPC + beacon URL (blob reads)Same

Add comfortable headroom beyond the snapshot size: the database grows with the chain, and PathDB full nodes keep ~24 hours of state history (345,600 blocks at the 250 ms cadence) by default. Also plan for the Ethereum parent-chain endpoint: the docs accept one you run yourself or a third-party provider — our Ethereum RPC works, including &archive=1 if you want archive depth on the L1 side too.

Choose your state scheme first: HashDB vs PathDB

Nitro supports two state databases, and you cannot switch later without re-initializingfrom a snapshot built for the scheme you want — so decide now.

  • HashDB (default, any Nitro version): boots with --init.latest=pruned; pruning is manual and offline (--init.prune) and keeps state for the latest 128 blocks. On a chain the size of Arbitrum One, pruning runs can take days, and the node serves no RPC while pruning.
  • PathDB (Nitro v3.9.x+, recommended for archive): enable with --execution.caching.state-scheme=path; pruning is automatic and online, but PathDB nodes cannot validate blocks, and PathDB cannot boot via --init.latest — you must pass --init.url with a matching snapshot.

Run the full node (Arbitrum One)

Create the data directory first (the image runs as UID 1000; chmod -fR 777 the directory if you hit permission errors), then run:

mkdir -p /data/arbitrum

docker run --rm -it \
  -v /data/arbitrum:/home/user/.arbitrum \
  -p 0.0.0.0:8547:8547 -p 0.0.0.0:8548:8548 \
  offchainlabs/nitro-node:v3.11.3-beb2108 \
  --parent-chain.connection.url=<YOUR_ETHEREUM_RPC_URL> \
  --parent-chain.blob-client.beacon-url=<YOUR_BEACON_URL> \
  --chain.id=42161 \
  --node.feed.input.url=wss://arb1.arbitrum.io/feed \
  --init.latest=pruned \
  --http.api=net,web3,eth \
  --http.corsdomain=* --http.addr=0.0.0.0 --http.vhosts=* \
  --ws.port=8548 --ws.addr=0.0.0.0 --ws.origins=*

What the pieces do: the parent-chain flags point Nitro at Ethereum (execution RPC plus beacon for blobs); --chain.id=42161 selects Arbitrum One; the sequencer feedstreams live transactions from the sequencer (if you run more than one node, run a feed relay — one per datacenter is the official guidance); --init.latest=pruned downloads the official pruned snapshot from snapshot.arbitrum.foundation instead of syncing from genesis. Ports: 8547 HTTP RPC, 8548 WebSocket, 9642 sequencer feed. If your L1 node is on the same host, add --network host right after docker run. Want tracing? Extend to --http.api=net,web3,eth,arb,debug.

Archive node: the differences

An Arbitrum archive node is a full node that keeps the entire historical state. With PathDB (recommended on v3.9+), boot from the archive snapshot instead of --init.latest:

# find the current archive-path snapshot
curl https://snapshot.arbitrum.foundation/arb1/latest-archive-path.txt

# then replace the init flag with the snapshot URL and add the archive flags:
#   --execution.caching.archive
#   --execution.caching.state-scheme=path
#   --init.url https://snapshot.arbitrum.foundation/arb1/<SNAPSHOT>/

On Nitro versions before v3.10.0 also set --execution.caching.state-history=0explicitly (from v3.10.0 archive nodes default to the full chain). One caveat for deep history: pre-Nitro (“Classic”) Arbitrum data requires running the Classic node alongside Nitro with a classic-redirect — only worth it if you need pre-2022 state.

Verify it works

curl -s http://localhost:8547 -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'
# -> 0xa4b1 (42161)

curl -s http://localhost:8547 -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
# compare against a block explorer — you're synced when you're within a block or two

Default full nodes run in watchtower mode — they check assertions on-chain and log found incorrect assertion in watchtower mode if they ever disagree. For graceful shutdowns use docker stop --time=1800 $(docker ps -aq) so the node can flush its database cleanly.

The honest cost of self-hosting

Running Arbitrum infrastructure yourself means several terabytes of NVMe, a 64 GB-class machine, an Ethereum L1 endpoint (and beacon) dependency, snapshot downloads measured in terabytes, and pruning runs that take days on a chain this size. That’s the right trade for validators, heavy indexers, and anyone who needs guaranteed capacity — and overkill for everyone else. If you mainly need calls to Arbitrum, a provider endpoint gets you the same chain with none of the operational surface.

SwiftNodes serves Arbitrum One (chain 42161) over HTTP and WebSocket with flat-rate pricing and archive routing (&archive=1) on paid plans — and if this guide convinced you that you do want your own node, keep our method-support matrixhandy for what your node will and won’t serve. Grab a free key and point your stack at:

https://rpc.swiftnodes.io/rpc/arbitrum?key=YOUR_API_KEY
wss://rpc.swiftnodes.io/ws/arbitrum?key=YOUR_API_KEY

Related: run your own Ethereum node (the parent chain your Nitro node leans on), Arbitrum WebSocket gotchas, and trace_block support by chain.