> ## Documentation Index
> Fetch the complete documentation index at: https://docs.whitechain.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a node

> Prerequisites and step-by-step instructions to deploy a Whitechain RPC node with op-reth and op-node using Docker Compose.

Deploy an external Whitechain RPC node on your own server. By the end of this guide you will have a running `op-reth` + `op-node` pair that follows the canonical L2 chain and exposes JSON-RPC and WebSocket endpoints.

<Note>
  Available on Testnet today; Mainnet at launch.
</Note>

## Prerequisites

### Hardware

| Component | `full-snap-node` / `full-node`                                        | `archive-node`                           |
| --------- | --------------------------------------------------------------------- | ---------------------------------------- |
| CPU       | 4+ cores                                                              | 8+ cores                                 |
| RAM       | 16 GB                                                                 | 32 GB                                    |
| Storage   | NVMe SSD, 500 GB min / 1 TB recommended (2x current chain size + 20%) | NVMe SSD, sized for full history (1 TB+) |
| Network   | 100 Mbps+                                                             | 1 Gbps                                   |

Disk usage grows with the chain.

### Software

* A Linux server with a public IP.
* Docker with Compose v2.
* `make`, `git`, `openssl`, `curl`, `jq`. `make up` uses `jq` to cross-check the artifacts before it starts anything, so the node does not come up without it.

### L1 RPC and Beacon

You need your own Ethereum L1 RPC and Beacon endpoints. `op-node` reads L1 batches through the RPC. It reads blob data through the Beacon API, since Whitechain batches are posted to L1 as EIP-4844 blobs, and blobs are only retrievable through the Beacon API, not the execution RPC. A regular execution-only endpoint is not enough; whatever you use must expose both.

Run your own L1 node, or use a provider that offers a matching pair of endpoints for the network below. Not every provider exposes a Beacon API on its free tier, so confirm both endpoints respond before filling in `.env`.

| Whitechain network | L1 chain         |
| ------------------ | ---------------- |
| Whitechain mainnet | Ethereum mainnet |
| Whitechain Sepolia | Ethereum Sepolia |

### Files from the Whitechain team

* `genesis.json` (L2 execution genesis) and `rollup.json` (OP rollup configuration) for your network. Both are published, with checksums and a regeneration recipe, in the [whitechain-bootstrap repository](https://github.com/whitechain-labs/whitechain-bootstrap). See [Network artifacts](/operate/run-a-node/network-artifacts).
* `WHITECHAIN_PUBLIC_RPC`: the public Whitechain RPC URL, used as the transaction-forwarding target.
* `WHITECHAIN_RETH_TRUSTED_PEERS`: a trusted reth enode to snap-sync from (required for `full-snap-node`).
* `WHITECHAIN_PUBLIC_OP_NODE_P2P` (optional): a static op-node peer.

<Note>
  The node repository ships no copy of `genesis.json` and `rollup.json`, and no checksum file of its own, so there is a single source of truth to check against. Copy both files in from [whitechain-bootstrap](https://github.com/whitechain-labs/whitechain-bootstrap) and compare their SHA-256 against the hashes published there. For testnet, `.env.testnet.example` already ships with working values for the rest. You only need to request values from the Whitechain team for mainnet.
</Note>

## Set up the node

1. Get the `public-rpc-node` manifests onto your server, from the [whitechain-labs/node repository](https://github.com/whitechain-labs/node).

2. Copy the network artifacts into `artifacts/<network>/`. They are not shipped in the node repository. The folder name must match `WHITECHAIN_NETWORK` in `.env`. See [Network artifacts](/operate/run-a-node/network-artifacts) for where to download them and how to verify them.

   ```bash theme={null}
   git clone https://github.com/whitechain-labs/whitechain-bootstrap.git
   cd whitechain-bootstrap
   shasum -a 256 testnet/genesis.json testnet/rollup.json
   cp testnet/genesis.json testnet/rollup.json <node-repo>/artifacts/testnet/
   ```

   ```text theme={null}
   artifacts/testnet/genesis.json
   artifacts/testnet/rollup.json
   ```

   Do not skip the hash comparison. `genesis.json` decides which chain your node treats as canonical, and `rollup.json` decides how it derives that chain, so a wrong or tampered file puts the node on a different chain.

3. Create your `.env` from the example and fill in the required values.

   ```bash theme={null}
   cp .env.testnet.example .env   # or .env.mainnet.example
   ```

   ```bash theme={null}
   WHITECHAIN_NETWORK=testnet
   PUBLIC_IP=203.0.113.10
   WHITECHAIN_PUBLIC_RPC=https://rpc.testnet.whitechain.io

   L1_RPC_URL=https://your-l1-rpc.example.com
   L1_BEACON_URL=https://your-l1-beacon.example.com
   L1_RPC_KIND=basic

   # required for full-snap-node
   WHITECHAIN_RETH_TRUSTED_PEERS=enode://<pubkey>@<ip>:30303
   ```

   For the full list of variables, see [Node configuration](/operate/run-a-node/configuration).

   `HTTP_API` and `WS_API` are `eth,net,web3,rpc` by default on every profile. Read [RPC namespaces](/operate/run-a-node/configuration#rpc-namespaces) before you widen them.

4. Start the profile you chose.

   ```bash theme={null}
   make up-full-snap-node   # recommended default: pruned, snap-syncs from a trusted peer
   # make up-full-node      # pruned, consensus-layer sync (re-executes from L1)
   # make up-archive-node   # archive node
   ```

   `make up` validates `.env`, cross-checks the two artifacts against each other (see [Artifact validation](/operate/run-a-node/network-artifacts#artifact-validation)), generates `keys/<profile>/jwt.txt` if missing, then runs `docker compose --profile <profile> up -d`.

5. Confirm the node responds on the profile's HTTP port.

   ```bash theme={null}
   curl -s -X POST http://127.0.0.1:8545 \
     -H 'Content-Type: application/json' \
     --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false],"id":1}'
   ```

<Warning>
  For `full-node` and `archive-node`, initial sync from genesis re-executes every transaction and can take from minutes on a fresh testnet to many hours on a long-running chain. There are no published database snapshots to cut this down. Use `full-snap-node` instead if you need a fast bootstrap: it snap-syncs from its trusted peer and typically completes in about an hour on testnet.
</Warning>

## Verify the sync

Watch the logs with `make logs-full-snap-node` (or `logs-full-node` / `logs-archive-node`). In `op-node` you should see `Connected to L1 Beacon API` and `started p2p host` with your local peerID early on. What follows depends on the profile's sync method:

* `full-snap-node` (execution-layer / snap): `Starting EL sync`, then repeating `Inserting unsafe L2 execution payload to drive EL sync` and `Inserted new L2 unsafe block` lines. These appear as blocks are pulled from the trusted peer and applied to `op-reth`.
* `full-node` / `archive-node` (consensus-layer): repeating `Advancing bq origin` lines (L1 batch derivation), then `Inserted new L2 unsafe block` lines as `op-reth` re-executes each block.

<Note>
  Underneath this, `op-reth` runs its own staged sync pipeline (14 stages) independently of what `op-node` reports. The RPC keeps reporting block `0` until the pipeline finishes, which is expected, not a hang. Watch the `op-reth` container logs directly: `docker logs -f whitechain-<profile>-op-reth 2>&1 | grep --line-buffered -iE "stage=|received headers|finished stage"`. Header download logs `Received headers ... to_block=N`; later stages log `checkpoint=X target=Y`.
</Note>

<Note>
  In the first few minutes after start, the node may report no peers ready to handle block requests until the static peer handshake completes. Wait for a connected peer to appear before treating this as an error.
</Note>

<Note>
  `op-node` RPC on `9545` is bound to loopback (`127.0.0.1`) only, on every profile. Query it from the host the node runs on, not over the network.
</Note>

Check how far the node is behind the wall clock:

```bash theme={null}
echo "behind by $((($(date +%s) - $( \
  curl -s -X POST http://127.0.0.1:9545 \
    -H 'Content-Type: application/json' \
    --data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \
  | jq -r .result.unsafe_l2.timestamp)) / 60)) minutes"
```

Check connected peers:

```bash theme={null}
curl -s -X POST http://127.0.0.1:9545 \
  -H 'Content-Type: application/json' \
  --data '{"jsonrpc":"2.0","method":"opp2p_peers","params":[true],"id":1}' \
  | jq '.result.totalConnected'
```

## Related

* [Node operators overview](/operate/run-a-node/overview)
* [Network artifacts](/operate/run-a-node/network-artifacts)
* [Node configuration](/operate/run-a-node/configuration)
* [Node maintenance](/operate/run-a-node/maintenance)
* [Troubleshooting](/operate/run-a-node/troubleshooting)
