Skip to main content

Running a Read-Only RPC Node

This page walks through the process of running a read-only OXN RPC node. Read Hardware Requirements first — SGX-capable hardware is a hard prerequisite.

Docs status

The step-by-step commands below are guidance based on the current node architecture. Some specific image tags, config paths, and command flags may change; check the OXN releases or contact the team via Support for the latest.

Prerequisites

Confirm you have:

  • SGX-capable hardware with /dev/sgx_enclave and /dev/sgx_provision present.
  • Docker installed (20.10 or newer).
  • Sufficient disk space (100+ GB for testnet).
  • The Intel DCAP QCNL configured (/etc/sgx_default_qcnl.conf).

Verify the SGX device nodes:

ls -la /dev/sgx_enclave /dev/sgx_provision
# Expected: two character device nodes with the correct owner

Docker-based deployment

The recommended way to run an OXN node is via Docker. Pull the node image:

docker pull zkpchain/sapphire-localnet:latest # placeholder tag; consult latest release

Prepare a data directory on the host:

sudo mkdir -p /data/oxn-node
sudo chown $USER /data/oxn-node

Start the container:

docker run -d \
--name oxn-rpc-node \
--restart unless-stopped \
-v /data/oxn-node:/serverdir/node \
-v /var/run/aesmd:/var/run/aesmd \
-v /etc/sgx_default_qcnl.conf:/etc/sgx_default_qcnl.conf:ro \
--device /dev/sgx_enclave \
--device /dev/sgx_provision \
-p 8545:8545 \
zkpchain/sapphire-localnet:latest

Key flags:

  • -v /data/oxn-node:/serverdir/node — persistent chain state.
  • -v /var/run/aesmd:/var/run/aesmd — SGX AESM service socket.
  • --device /dev/sgx_enclave --device /dev/sgx_provision — SGX access.
  • -p 8545:8545 — JSON-RPC endpoint.

Waiting for sync

Initial sync takes time — often 5+ minutes for a fresh testnet node depending on chain size. Monitor with:

docker logs -f oxn-rpc-node

Look for Total: or Available: lines indicating the chain has reached ready state.

Query the node once it's up:

curl http://localhost:8545 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_chainId","id":1}'
# Expected: {"jsonrpc":"2.0","id":1,"result":"0xba"}

Exposing to your application

If your dApp runs on the same machine, point it at http://localhost:8545. For remote access, put a reverse proxy (nginx, Caddy) in front with TLS:

server {
listen 443 ssl;
server_name your-node.example.com;

ssl_certificate /etc/letsencrypt/live/your-node.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-node.example.com/privkey.pem;

location / {
proxy_pass http://127.0.0.1:8545;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_buffering off;
proxy_read_timeout 1d;
}
}

Do not expose the node without authentication or IP-based access control — anyone hitting it can consume your node's resources.

Configuration options

The default configuration serves standard eth_* JSON-RPC methods. Adjustments you may want:

  • Archive vs pruned — control historical state retention.
  • CORS policy — for browser-based dApps hitting the node directly.
  • debug_* and trace_* methods — disabled by default; enable if you need them for debugging.
  • WebSocket endpoint — separate port, off by default in some configurations.

Specific configuration paths and syntax depend on the node image release. Contact Support for current specifics.

Monitoring

Basic health checks:

# Latest block height
curl -s http://localhost:8545 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","id":1}' | jq .

# Sync status
curl -s http://localhost:8545 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_syncing","id":1}' | jq .

For continuous monitoring, scrape a Prometheus metrics endpoint if the node exposes one. Alert on:

  • Node stopped syncing (block height not advancing).
  • Disk usage above threshold.
  • SGX enclave errors in logs.
  • Container restart loops.

Upgrading

When a new node image is released:

  1. Read the release notes for breaking changes.
  2. Stop the running container: docker stop oxn-rpc-node.
  3. Pull the new image.
  4. Recreate the container with the same volumes.
  5. Verify the node syncs and serves requests.

State persists across upgrades because it lives in the host-mounted volume.

Common issues

"Container fails to start with SGX error." Verify /dev/sgx_enclave and /dev/sgx_provision exist and the container has access. Check BIOS SGX setting and kernel version.

"Node is stuck at height 0 or a low number." Sync is in progress. Testnet initial sync takes minutes. Check docker logs for errors.

"eth_chainId returns wrong value." You may be talking to a local Hardhat network by mistake. Confirm you're hitting the OXN node's port.

"AESM service errors in logs." Install sgx-aesm-service on the host and confirm the socket exists at /var/run/aesmd/aesm.socket.

Next steps