Advanced Node Operations

Manual runtimes, storage, services, gateways, and detailed diagnostics.

Run a full or archive ROKO node

This testnet guide targets a supported Linux distribution with systemd and Chrony. Use a dedicated machine or VM, service account, and data volume.

1. Prepare capacity

Measure instead of relying on a permanent minimum:

  • sustained P2P bandwidth and latency;
  • database write latency and IOPS;
  • memory pressure and swap activity;
  • file descriptors;
  • data-volume bytes/inodes and growth per day.

For an archive, use a dedicated fast volume and alert before 80% utilization. The OS/root volume should have enough independent space to boot, update, and log even when chain data is large.

2. Obtain trusted software and chain identity

Public node operators do not need access to the private ROKO source repositories. Choose one published runtime:

  • the architecture-specific image from

`ghcr.io/roko-network/roko-node`; or

  • the native Linux binary from `downloads.roko.network`, obtained over HTTPS

or through the official torrent.

Detect the host architecture:

case "$(uname -m)" in
  x86_64) ROKO_ARCH=amd64 ;;
  aarch64|arm64) ROKO_ARCH=arm64 ;;
  *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
esac

For Docker:

ROKO_IMAGE="ghcr.io/roko-network/roko-node:testnet-latest-${ROKO_ARCH}"
docker pull "$ROKO_IMAGE"
docker image inspect "$ROKO_IMAGE" \
  --format 'digest={{index .RepoDigests 0}} revision={{index .Config.Labels "org.opencontainers.image.revision"}}'
docker run --rm "$ROKO_IMAGE" --version

Record the resolved digest and revision before deployment.

For the native binary:

ROKO_RELEASE_BASE=https://downloads.roko.network/releases/current
ROKO_BUNDLE="roko-node-testnet-linux-${ROKO_ARCH}.tar.gz"
curl --fail --location --remote-name "$ROKO_RELEASE_BASE/$ROKO_BUNDLE"
curl --fail --location --remote-name "$ROKO_RELEASE_BASE/SHA256SUMS"
sha256sum --check --ignore-missing SHA256SUMS
tar -xzf "$ROKO_BUNDLE"
./roko-node --version
sudo install -o root -g root -m 0755 roko-node /usr/local/bin/roko-node

The same archives and checksum manifest are available from the official binary and image torrent and magnet URI. Verify the selected archive before extraction. See the peer-assisted download guide for safe seeding.

Do not use third-party binaries, guessed image names, `curl | sh`, or instructions that ask you to clone the private node repository.

Download all scripts with their checksum manifest, verify them, and inspect the runtime installer before execution:

mkdir roko-install && cd roko-install
ROKO_SCRIPTS=https://downloads.roko.network/scripts
for file in SHA256SUMS install-roko-native.sh install-roko-docker.sh \
  bootstrap-roko-chain-spec.sh install-roko-service.sh; do
  curl --fail --location --remote-name "$ROKO_SCRIPTS/$file"
done
sha256sum --check SHA256SUMS

less install-roko-native.sh
bash install-roko-native.sh
bash bootstrap-roko-chain-spec.sh
bash install-roko-service.sh \
  --runtime native --node-name YOUR_NODE --start

For Docker, inspect and run `install-roko-docker.sh`, then select `--runtime docker` in the service step. For a registry-free installation, download the matching `roko-node-testnet-docker-*.tar.gz`, verify it against the release `SHA256SUMS`, and pass it as `install-roko-docker.sh --archive FILE`.

Every script supports `--help` and `--dry-run`. Never pipe a remote script directly into a shell.

Until a release publishes the current testnet chain spec as a pinned artifact, it can be exported from the public RPC for testnet use:

ROKO_RPC_URL=https://rpc.roko.network
curl --fail --silent --show-error --max-time 30 "$ROKO_RPC_URL" \
  -H 'content-type: application/json' \
  --data '{"jsonrpc":"2.0","id":1,"method":"sync_state_genSyncSpec","params":[true]}' \
  --output /tmp/roko-sync-spec-response.json
python3 - <<'PY'
import json
from pathlib import Path

response = json.loads(Path("/tmp/roko-sync-spec-response.json").read_text())
if response.get("error") is not None or not isinstance(response.get("result"), dict):
    raise SystemExit("RPC did not return a chain-spec object")
Path("/tmp/roko-testnet-v2.json").write_text(
    json.dumps(response["result"], indent=2) + "\
"
)
PY
sudo install -d -o root -g root -m 0755 /etc/roko
sudo install -o root -g root -m 0644 /tmp/roko-testnet-v2.json \
  /etc/roko/roko-testnet-v2.json
sha256sum /etc/roko/roko-testnet-v2.json

This bootstrap depends on the public RPC and is therefore testnet-only. A production launch must publish and pin the chain spec independently. Do not pipe the chain spec through a JSON implementation that rounds wide integers.

3. Bootstrap the clock

Configure at least three or four permitted, diverse Chrony sources. ROKO's public NTP service can be one input:

server time.roko.network iburst
pool pool.ntp.org iburst maxsources 3
makestep 0.1 3
rtcsync

Restart Chrony, then require healthy tracking before starting the chain:

sudo systemctl restart chrony
chronyc waitsync 60 0.01
chronyc tracking
chronyc sources -v

`waitsync 60 0.01` waits for a correction below 10 ms. Validators should set a tighter gate supported by their sources and deployment.

4. Create the service account and data path

Example:

sudo useradd --system --home-dir /var/lib/roko --create-home \
  --shell /usr/sbin/nologin roko
sudo install -d -o roko -g roko -m 0750 /var/lib/roko

Mount the intended chain-data volume at `/var/lib/roko` before the service starts. Use a stable filesystem identifier in `/etc/fstab` and test a reboot.

5. Create a full-node service

# /etc/systemd/system/roko-node.service
[Unit]
Description=ROKO full node
Wants=network-online.target
After=network-online.target chrony.service
RequiresMountsFor=/var/lib/roko

[Service]
Type=simple
User=roko
Group=roko
ExecStartPre=/usr/bin/chronyc waitsync 60 0.01
ExecStart=/usr/local/bin/roko-node \
  --chain /etc/roko/roko-testnet-v2.json \
  --base-path /var/lib/roko \
  --name <NODE_NAME> \
  --bootnodes /dns4/boot.roko.network/tcp/30333/ws/p2p/12D3KooWKSBZRtSiGKo8ueJtazCHT89LaBi6ZAtzgbeznf4NtVGj \
  --port 30333 \
  --rpc-port 9944 \
  --rpc-methods Safe
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/lib/roko

[Install]
WantedBy=multi-user.target

RPC remains loopback-only because `--rpc-external` is absent. Allow inbound TCP/30333 only if you want other peers to dial this node. Do not expose RPC, Prometheus, a database, or administration ports without a separate reviewed gateway policy.

For an archive, add:

--pruning archive

Do not run full and archive services concurrently against the same base path.

Enable and inspect:

sudo systemctl daemon-reload
sudo systemctl enable --now roko-node
sudo systemctl status roko-node
journalctl -u roko-node --since today

6. Verify before relying on the node

Query loopback RPC:

curl --fail --silent http://127.0.0.1:9944 \
  -H 'content-type: application/json' \
  --data '[
    {"jsonrpc":"2.0","id":1,"method":"system_health","params":[]},
    {"jsonrpc":"2.0","id":2,"method":"system_localPeerId","params":[]},
    {"jsonrpc":"2.0","id":3,"method":"system_syncState","params":[]},
    {"jsonrpc":"2.0","id":4,"method":"chain_getBlockHash","params":[0]},
    {"jsonrpc":"2.0","id":5,"method":"chain_getFinalizedHead","params":[]}
  ]'

The genesis hash must match `0x0a2296f8f036f71437e8f6f2028ccbf0dc3dd6b3de9120fc15e43789c794e8bb`. Wait until `isSyncing` is false and the finalized head advances.

Record the peer ID, restart the host, and verify:

1. the data volume mounted; 2. Chrony synchronized before the node started; 3. the peer ID is unchanged; 4. peers reconnect; and 5. the finalized head continues to advance.

The libp2p identity lives under the base path. Back it up as sensitive material, but never print or pass its secret with `--node-key`.

7. Upgrade or rebuild

For an upgrade, verify the new artifact, stop the service, preserve the base path and node identity, replace the native binary atomically or update the recorded container digest, start, and repeat all health checks. Keep the previous checksum-matched binary or image digest for rollback.

Chain data is reconstructible from peers; identities and operator-owned keys are not. A database copy taken while the node is writing is not automatically a valid backup. Prefer a clean stop or a storage snapshot with documented consistency behavior.

References