Skip to main content

Node Configuration

Introduction

CKB uses configuration files stored in <config-dir>, which by default is the current working directory. You can change this using the -C <path> argument to specify a different directory. For example:

ckb -C node1 run
  • This command tells CKB to use the node1/ directory as the config directory, where it expects to find ckb.toml and related files.

Different subcommands expect different config filenames:

  • ckb run uses ckb.toml
  • ckb miner uses ckb-miner.toml
  • ckb import and ckb export also use ckb.toml

The ckb init command helps initialize a config directory by generating the necessary files. Some config files may refer to other files, such as chain.spec in ckb.toml, or system_cells in a chain spec file. These referenced paths can be either absolute or relative to the config file’s own location. For example, with this directory structure:

ckb.toml
└── specs/dev.toml
└── cells/secp256k1_sighash_all
  • ckb.toml would refer to specs/dev.toml
  • dev.toml would refer to the cell file as cells/secp256k1_sighash_all

This article covers the following configuration topics:

Light Client Support & WSS Access

CKB full nodes support the Light Client Protocol by default. No configuration is needed — if you're running a standard full node, it will automatically respond to light client peers using the built-in P2P protocol.

Browsers cannot connect to P2P networks directly. Instead, they must connect to your node over WebSocket with TLS (wss://). To support this, you need to deploy a TLS proxy in front of your node that converts WSS traffic into standard TCP.

Prerequisites for WSS Setup

Before you begin, ensure the following:

  • Your CKB node running and listening on its default P2P port (8115)
  • You have deployed a CKB node (v0.200.0 or later) and it is running normally.
  • You own a domain name and can modify its DNS records (e.g., via Cloudflare, Namecheap, or Alibaba Cloud).
  • You have a valid TLS certificate for your domain (You can use a commercial provider like DigiCert or a free tool like Certbot.)
  • Your server has ports 80 and 443 open to the public.
  • Nginx is installed with the Stream module enabled, which will be used to forward encrypted WebSocket traffic to the CKB node.

Check If Nginx Has the Stream Module

nginx -V 2>&1 | grep -- --with-stream

If you see --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module, you're good to go.

If not, you must recompile Nginx with these flags:

./configure \
--prefix=/usr/local/nginx \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module
Working Example of Nginx Config

Here’s a working example that:

  • Routes TCP (P2P) and WSS traffic differently based on TLS version
  • Proxies WSS traffic to a separate internal port (8443)

You need to replace:

  • ckb.example.com with your domain
  • 8118 with your node’s P2P port
  • 443 with the external public port
  • TLS cert paths with your actual file paths
# Global settings
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 768;
}

# TCP/TLS stream routing
stream {
log_format stream_log '$remote_addr - $remote_port [$time_local] '
'Protocol: $ssl_preread_protocol '
'Status: $status '
'Bytes_Sent: $bytes_sent '
'Bytes_Received: $bytes_received '
'Session_Time: $session_time '
'Upstream: $upstream_addr';

map $ssl_preread_protocol $upstream {
default backend_tcp;
"TLSv1.2" backend_wss_http;
"TLSv1.3" backend_wss_http;
}

upstream backend_tcp {
server 127.0.0.1:8118;
}

upstream backend_wss_http {
server 127.0.0.1:8443;
}

server {
listen 443;
proxy_pass $upstream;
ssl_preread on;

access_log /var/log/nginx/stream_access.log stream_log;
error_log /var/log/nginx/stream_error.log;
}
}

# WSS HTTP proxy (for browsers)
http {
sendfile on;
keepalive_timeout 65;
client_max_body_size 10m;

include /etc/nginx/mime.types;
default_type application/octet-stream;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

gzip on;

server {
listen 8443 ssl;
server_name ckb.example.com;

ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;

location / {
proxy_pass http://127.0.0.1:8118;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
}

Traffic Routing Summary

Client TypeRoute
TCPTCP Client -> ckb.example.com:443 -> Nginx (stream, ssl_preread) -> backend_tcp -> [ckb node 8118]
WSSWSS Client -> ckb.example.com:443 -> Nginx (stream, ssl_preread) -> backend_wss_http -> 127.0.0.1:8443 -> Nginx (http, TLS decryption, WebSocket) -> [ckb node 8118]

Reload Nginx

sudo nginx -t
sudo nginx -s reload

Add DNS Record

Go to your DNS provider and add an A record pointing ckb.example.com to your server’s public IP.

Modify Config to Advertise Your Public Address

Uncomment the public_addresses in your ckb.toml.

### Specify the public and routable network addresses
public_addresses = ["/dns4/ckb.example.com/tcp/443"]

Remember to replace ckb.example.com with your own domain.

Then restart your CKB node.

Verify Configuration

  1. Check your node’s public address:
curl -s -H "Content-Type: application/json" \
-d '{ "id": 2, "jsonrpc": "2.0", "method": "local_node_info", "params": [] }' \
http://127.0.0.1:8114 | jq '.result.addresses[].address'
  1. Use it as a bootnode in another node

Initialize a new CKB node (v.0.200.0 or later). Update the bootnodes section in ckb.toml to the following:

bootnodes = ["/dns4/ckb.example.com/tcp/443/p2p/<PeerID>"]

Remember to replace <PeerID> with the one you retrieved from step 1. For the wasm-based light client in browsers, the address should start with wss:

bootnodes = ["/dns4/ckb.example.com/tcp/443/wss/p2p/<PeerID>"]
  1. Start the second node

Start the second node and check the logs. If it begins syncing blocks successfully, your WSS setup is complete.

Proxy and Onion Routing Support

CKB supports advanced networking configurations for users who want to:

  • Preserve privacy by hiding their node’s IP address
  • Route traffic through a proxy (e.g., SOCKS5)
  • Expose their node on the Tor network using an .onion address

These are useful for censorship resistance, secure relayers, and privacy-focused deployments.

ProxyConfig

The [network.proxy]section allows your node to route outbound P2P connections through a SOCKS5 proxy, such as the one provided by a Tor server.

[network.proxy]
proxy_url = "socks5://127.0.0.1:9050"
proxy_random_auth = true
  • proxy_url: The URL of your SOCKS5 proxy.
    • Default Tor proxy: socks5://127.0.0.1:9050
    • If you're running a local Tor server, this will work out of the box.
  • proxy_random_auth : When enabled, CKB generates a random username and password per connection, improving privacy (like Tor's IsolateSOCKSAuth).
    • Recommended for Tor usage
    • If using a non-Tor proxy that supports but doesn’t require authentication, you may need to set this to false to avoid connection failures.

OnionConfig

The [network.onion]section in ckb.toml allows your node to act as a Tor hidden service, accepting inbound connections over the .onion network.

[network.onion]
listen_on_onion = true
onion_service_target = "127.0.0.1:8115"
onion_server = "127.0.0.1:9050"
tor_controller = "127.0.0.1:9051"
tor_password = ""
  • listen_on_onion: Enables listening for incoming connections over the Tor network. If true, your node will publish a .onion address and accept Tor traffic.
  • onion_service_target: The local address your Onion service will forward to — usually your CKB node’s P2P port. It sets to 127.0.0.1:8115 by default.
  • onion_server: SOCKS5 proxy used to connect to other .onion addresses.
    • If unset, CKB will use the proxy defined in [network.proxy].
  • tor_controller: The address of the Tor ControlPort, which CKB uses to register or manage Onion services. It sets to 127.0.0.1:9051 by default.
  • tor_password: Password used to authenticate with the Tor ControlPort.
    • You can leave it empty if the Tor ControlPort allows unauthenticated access (not recommended for production).
    • The password must match the HashedControlPassword in your torrc file.

Fee Estimator

The Fee Estimator is an experimental feature introduced in CKB v0.120.0 to help developers and users determine optimal transaction fee rates based on recent block activity.

To use the Fee Estimator, you must:

  1. Specify a fee estimation algorithm in ckb.toml
[fee_estimator]
## Specifies the fee estimates algorithm. Current algorithms: ConfirmationFraction, WeightUnitsFlow.
algorithm = "WeightUnitsFlow"
  1. Make sure the Experiment module is included in the list in ckb.toml . This module is enabled by default.
# List of API modules: ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment", "Debug", "Indexer", "RichIndexer"]
modules = ["Net", "Pool", "Miner", "Chain", "Stats", "Subscription", "Experiment"]

Once your node is running and synced, you can query the estimated fee rate using:

echo '{ "id": 1, "jsonrpc": "2.0", "method": "estimate_fee_rate", "params": [] }' \
| curl -s -H "Content-Type: application/json" -d @- "http://localhost:8114" \
| jq

result:

{
"jsonrpc": "2.0",
"result": "0x3e8",
"id": 1
}

Check out this spec to learn more about fee estimator.

Run Multiple Nodes

You can run multiple CKB nodes on the same machine (e.g., for local Devnet testing) by setting up separate configuration directories and customizing their ports.

  1. Create separate directories for each node by running :
mkdir node1 node2
  1. Initialize each node with the same dev chain and genesis message.

Each CKB node requires its own configuration directory. You can specify the directory using the -C <path> option, which tells CKB where to store the node’s config files and chain data. When using the dev chain, nodes will generate a random genesis block unless you explicitly set the same --genesis-message. Nodes with different genesis blocks cannot connect to each other, so it’s important to use the same message across all Devnet nodes.

ckb -C node1 init --chain dev --genesis-message dev-genesis
ckb -C node2 init --chain dev --genesis-message dev-genesis

dev-genesis is just an example — you can replace it with any string as long as it’s identical.

note

genesis-message is only required for the dev chain. Mainnet and testnet use fixed genesis blocks and do not require --genesis-message.

  1. Edit node2/ckb.toml to avoid port conflicts: In your node2’s ckb.toml, change the default ports:
    • RPC port (8114) → 8116
    • P2P port (8115) → 8117
[rpc]
listen_address = "127.0.0.1:8116"

[p2p]
listen_address = "/ip4/0.0.0.0/tcp/8117"
  1. Start node1:
ckb -C node1 run
  1. Optional: Connect node2 to node1
  • Find the P2P address from node1 logs (e.g., /ip4/127.0.0.1/tcp/8115/p2p/PeerID)
  • Add it to bootnodes in node2/ckb.toml:
bootnodes = ["/ip4/127.0.0.1/tcp/8115/p2p/PeerID"]

Remeber to replace PeerID with your actual one.

  1. Start node2:
ckb -C node2 run