Skip to main content

Set Up a Telos Block Producer

This guide configures a new or replacement block producer on a Telos network where Savanna instant finality is already active.

A production BP has two separate signing responsibilities:

  • a K1 block-signing key signs blocks produced during the BP's scheduled rounds;
  • a BLS finalizer key votes on blocks so the network can form quorum certificates and finalize them.

The finalizer is part of the producer's nodeos process. It is not a separate daemon.

Before you begin

Complete these prerequisites:

  • Review the producer system requirements.
  • Install TelosZero Core.
  • Obtain a registered Telos account for the BP.
  • Keep the account owner and active keys on a separate control/signing host. Do not store them on the producer.
  • Generate a dedicated K1 block-signing key. Never use the BP account's active key to sign blocks.
  • Prepare at least two private relay/sentry paths to the public Telos P2P network.
  • Publish the BP's chains.json and bp.json metadata over HTTPS.
Do not expose the producer

The producer HTTP API should bind only to localhost. Its P2P listener should be reachable only by the BP's private relays or explicitly allowed peers. Run public API, SHiP, and history workloads on separate nodes.

1. Prepare BP metadata

Host chains.json and bp.json under the base URL you will register on-chain. Include the BP organization, location, public API endpoints, public P2P endpoints, and producer information. Follow the BP metadata standard and validate the published files as JSON.

The registered URL is the base website URL, not the full path to bp.json.

Registered URL: https://bp.example
Metadata: https://bp.example/bp.json

The Telos validator dashboard discovers public API and P2P endpoints from this metadata. It cannot inspect the private producer host.

2. Configure the private producer

Create /etc/telos/mainnet-primary/config.ini and replace every placeholder:

# Private management API only
http-server-address = 127.0.0.1:8888
http-validate-host = false

# Bind this to a private interface reachable by your relays
p2p-listen-endpoint = <PRIVATE_PRODUCER_IP>:9876
agent-name = "<BP_ACCOUNT>-producer"

# The TelosZero 1024 MiB default is too small for current Telos state.
chain-state-db-size-mb = 32768
protocol-features-dir = /var/lib/telos/mainnet-primary/protocol_features

# Minimal producer plugins
plugin = eosio::http_plugin
plugin = eosio::chain_plugin
plugin = eosio::chain_api_plugin
plugin = eosio::net_plugin
plugin = eosio::producer_plugin

# Producer identity and the dedicated K1 block-signing key
producer-name = <BP_ACCOUNT>
signature-provider = <PUB_K1_BLOCK_KEY>=KEY:<PVT_K1_BLOCK_KEY>

# Savanna finalizer; generate these values in the next guide
signature-provider = <PUB_BLS_FINALIZER_KEY>=KEY:<PVT_BLS_FINALIZER_KEY>
vote-threads = 4
finalizers-dir = /var/lib/telos/finalizers/mainnet-primary
production-pause-vote-timeout-ms = 6000

# Connect only to BP-controlled relay/sentry nodes
p2p-peer-address = <PRIVATE_RELAY_A>:9876
p2p-peer-address = <PRIVATE_RELAY_B>:9876

chain-id is not a valid nodeos configuration option. The chain is selected by the node's genesis or snapshot state. Verify the resulting chain_id through get_info after startup as shown below.

The 32768 MiB chain-state capacity is a reviewed starting point for a host with the recommended 64 GB RAM. Keep it below usable physical memory and raise it deliberately as measured chain state grows.

Protect the file because it contains signing material:

sudo chown root:telos /etc/telos/mainnet-primary/config.ini
sudo chmod 0640 /etc/telos/mainnet-primary/config.ini

The explicit protocol-features-dir keeps nodeos's writable generated protocol feature files under the instance data directory, so the key-bearing configuration can remain root-owned and read-only to the service account.

Do not copy any of these legacy settings from the old BP guide:

# Invalid, removed, or unsafe for a current production BP:
# wasm-runtime = wabt
# plugin = eosio::history_plugin
# producer-threads = ...
# enable-stale-production = true

vote-threads = 4 is the producer default in TelosZero Core, but keep it explicit so the intended finalizer role is auditable. A relay that must forward votes also needs an explicit non-zero value; see Configure vote relays.

Keep production-pause-vote-timeout-ms = 6000. Setting it to 0 disables the guard that pauses block production when recent finalizer votes disappear.

3. Add logging

Create /etc/telos/mainnet-primary/logging.json using your normal centralized logging policy. At minimum, retain nodeos, P2P, producer, and vote/finality logs long enough to investigate missed blocks, missed votes, forks, and failovers.

If logging.json is stored in the config directory, nodeos loads it automatically.

4. Create a systemd service

Create /etc/systemd/system/telos-nodeos@.service:

[Unit]
Description=TelosZero Core node (%i)
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=telos
Group=telos
UMask=0077
WorkingDirectory=/var/lib/telos/%i
ExecStart=/usr/bin/nodeos --config-dir=/etc/telos/%i --data-dir=/var/lib/telos/%i
Restart=on-failure
RestartSec=5
TimeoutStopSec=300
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target

Load the service definition, but do not start it until the finalizer key is present in config.ini:

sudo systemctl daemon-reload
sudo systemctl enable telos-nodeos@mainnet-primary

5. Generate and configure the finalizer

Complete the first two sections of Initial finalizer setup now:

  1. generate a unique BLS key and proof of possession for this instance;
  2. place its signature-provider entry in config.ini;
  3. confirm the persistent finalizers-dir permissions.

Then return here to start and sync the node. Register the BP account before submitting regfinkey.

The first regfinkey for a producer becomes that producer's active finalizer key automatically. Do not run actfinkey for an initial key. actfinkey is for switching to a second, already registered key.

6. Start and sync the node

Replacing an already scheduled producer

Start the replacement with pause-on-startup = true. This pauses K1 block production while still allowing finalizer voting. Prove the old K1 signer is stopped and fenced, and use a new BLS key with its own safety history, before removing the pause and restarting. Never enable the same K1 key on two hosts at once, and never share or reuse a BLS key between hosts.

For a new data directory, perform the one-time snapshot start from the installation guide. For subsequent starts:

sudo systemctl start telos-nodeos@mainnet-primary
sudo systemctl status telos-nodeos@mainnet-primary
sudo journalctl -u telos-nodeos@mainnet-primary -f

Confirm the local node is on mainnet and at head:

curl -s http://127.0.0.1:8888/v1/chain/get_info \
| jq '{chain_id, server_full_version_string, head_block_num, last_irreversible_block_num, head_block_time, head_block_producer}'

Required checks:

  • chain_id exactly matches the Telos mainnet chain ID;
  • head_block_num advances continuously;
  • head_block_time is current;
  • the node remains close to the network head and irreversible block;
  • logs show no key parsing, finalizer safety, fork, or persistent P2P errors.

Do not register the first finalizer key until this process is running with the BLS key loaded.

7. Register the producer

Run governance transactions from the separate control/signing host. Set the public values:

export RPC=https://mainnet.telos.net
export BP_ACCOUNT=<BP_ACCOUNT>
export BLOCK_SIGNING_PUBLIC_KEY=<PUB_K1_BLOCK_KEY>
export BP_URL=https://bp.example
export BP_LOCATION=<UINT16_LOCATION>

Register or update the producer:

cleos -u "$RPC" system regproducer \
"$BP_ACCOUNT" \
"$BLOCK_SIGNING_PUBLIC_KEY" \
"$BP_URL" \
"$BP_LOCATION" \
-p "$BP_ACCOUNT@active"

BP_LOCATION is a numeric uint16 value. A city name is invalid. Use the value chosen for the BP's published location policy; use 0 only when no location value is being declared.

Confirm the producer row:

cleos -u "$RPC" system listproducers -l 200 \
| grep "$BP_ACCOUNT"

8. Register and verify the finalizer

Return to Register the first finalizer key. The first registration automatically selects that key in the contract table. Complete the table, native-policy, vote, relay, and backup checks before the BP enters the active schedule.

9. Production readiness checklist

Before accepting an active schedule slot, confirm all of the following:

  • The producer runs the approved TelosZero Core artifact and checksum.
  • Mainnet chain ID, head, and irreversible block are correct and advancing.
  • Account owner/active keys are absent from the producer host.
  • The K1 block-signing key is dedicated to block production.
  • The BLS key is unique to this nodeos instance and active on-chain.
  • vote-threads = 4 is set on the producer and every required relay hop.
  • production-pause-vote-timeout-ms = 6000 remains enabled.
  • finalizers-dir is persistent, local, mode 0700, and not on tmpfs.
  • No safety.dat or BLS key was copied from another host.
  • At least two independent relay paths carry blocks, transactions, and votes.
  • Producer HTTP and P2P ports are not exposed to the public internet.
  • The backup producer has its own pre-generated and pre-registered BLS key and starts with K1 production paused.
  • Block production, missed votes, finality, peer count, clock, disk, and process health are monitored.
  • Published chains.json/bp.json, API, SSL, and public P2P endpoints pass validators.telos.net.

The public validator checker cannot prove private key custody, producer configuration, relay vote propagation, or the integrity of safety.dat; those remain operator responsibilities.