Flare Validator Setup
This guide deploys a Flare mainnet validator node with Docker Compose and prepares the validator for staking and Entity registration.
A validator must not share the same node instance with public RPC service. Keep 9650 local or on a trusted private network, and expose only 9651/tcp publicly for P2P/staking.
Prerequisites
- Ubuntu 22.04/24.04 LTS
- Docker Engine 24+ and Docker Compose V2
jq,curl,openssl,xxd- Static public IP or stable port forwarding for
9651/tcp - Minimum self-bond: 1M FLR
- Recommended Entity pass conditions: 3M FLR active self-bond and 15M FLR active stake for earning staking passes
Step 1: Prepare Directories
sudo mkdir -p /data/flare/node/{db,conf/C,logs,staking}
sudo chown -R $USER:$USER /data/flare/node
cd /data/flare/node
Step 2: Create Secure C-Chain Config
{
"snowman-api-enabled": false,
"coreth-admin-api-enabled": false,
"coreth-admin-api-dir": "",
"eth-apis": ["web3"],
"continuous-profiler-dir": "",
"continuous-profiler-frequency": 900000000000,
"continuous-profiler-max-files": 5,
"rpc-gas-cap": 50000000,
"rpc-tx-fee-cap": 100,
"preimages-enabled": false,
"pruning-enabled": true,
"snapshot-async": true,
"snapshot-verification-enabled": false,
"metrics-enabled": true,
"metrics-expensive-enabled": false,
"local-txs-enabled": false,
"api-max-duration": 30000000000,
"ws-cpu-refill-rate": 0,
"ws-cpu-max-stored": 0,
"api-max-blocks-per-request": 30,
"allow-unfinalized-queries": false,
"allow-unprotected-txs": false,
"keystore-directory": "",
"keystore-external-signer": "",
"keystore-insecure-unlock-allowed": false,
"remote-tx-gossip-only-enabled": false,
"tx-regossip-frequency": 60000000000,
"tx-regossip-max-size": 15,
"log-level": "info",
"offline-pruning-enabled": false,
"offline-pruning-bloom-filter-size": 512,
"offline-pruning-data-directory": ""
}
This follows Flare's validator hardening guidance: minimal APIs, disabled admin APIs, pruning enabled, and metrics enabled.
Step 3: Create Docker Compose
services:
flare-node:
image: flarefoundation/go-flare:v1.13.0
container_name: flare-node
restart: unless-stopped
ports:
- "127.0.0.1:9650:9650"
- "0.0.0.0:9651:9651"
volumes:
- /data/flare/node/db:/app/db
- /data/flare/node/conf:/app/conf
- /data/flare/node/logs:/app/logs
# Mount the container default staking directory so signer.key generated
# on first boot is persisted on the host.
- /data/flare/node/staking:/root/.avalanchego/staking
environment:
NETWORK_ID: flare
AUTOCONFIGURE_BOOTSTRAP: "1"
AUTOCONFIGURE_PUBLIC_IP: "1"
AUTOCONFIGURE_BOOTSTRAP_ENDPOINT: https://flare-bootstrap.flare.network/ext/info
The official docs tell operators to find the latest stable go-flare Docker tag before deployment. This guide pins v1.13.0, checked on 2026-05-11. Re-check the release page before production updates.
Step 4: Generate and Persist Staking Keys
Flare's validator Entity registration requires staker.key and staker.crt. The official validator guide warns not to rely on throwaway auto-generated keys. Generate a compatible certificate/key pair before staking:
cd /data/flare/node/staking
openssl req -x509 -newkey rsa:4096 \
-keyout staker.key \
-out staker.crt \
-days 36500 \
-nodes \
-subj '/CN=localhost' \
-set_serial 0
chmod 600 staker.key
Start the node. Because /data/flare/node/staking is mounted to the container's default ~/.avalanchego/staking path, go-flare uses the generated staker.key and staker.crt, and auto-generates signer.key directly into the host directory on first boot:
cd /data/flare/node
docker compose up -d
docker compose logs -f flare-node
Verify the staking files are now present on the host:
ls -la /data/flare/node/staking
test -s /data/flare/node/staking/staker.key
test -s /data/flare/node/staking/staker.crt
test -s /data/flare/node/staking/signer.key
If you previously started the old compose file and signer.key exists only inside the container at ~/.avalanchego/staking/signer.key, copy it out before removing the container:
docker cp flare-node:/root/.avalanchego/staking/signer.key /data/flare/node/staking/signer.key
chmod 600 /data/flare/node/staking/signer.key
Then update the compose file to the default-path mount above and restart.
After signer.key appears, back up all three staking files:
ls -la /data/flare/node/staking
tar -czf /secure-backup/flare-staking-keys.tar.gz \
/data/flare/node/staking/staker.key \
/data/flare/node/staking/staker.crt \
/data/flare/node/staking/signer.key
staker.key, staker.crt, and signer.key define the node identity and proof of possession. Losing them after staking can lock funds against an unrecoverable NodeID until stake expiry.
Step 5: Open Firewall
sudo ufw allow 9651/tcp
sudo ufw deny 9650/tcp
If internal monitoring or a private FSP host needs RPC access, allow 9650/tcp only from trusted private IPs.
Step 6: Verify Sync and Node ID
curl -s http://127.0.0.1:9650/ext/health | jq
curl --data '{
"jsonrpc":"2.0",
"method":"info.getNodeID",
"id":1,
"params":{}
}' -H 'content-type:application/json;' \
http://127.0.0.1:9650/ext/info | jq -r ".result.nodeID"
The health response should eventually include "healthy": true. Initial sync can take hours or days depending on disk and network conditions.
Step 7: Self-Bond
Use the official Flare Stake Tool flow to self-bond FLR to your Node-ID.
| Requirement | Value |
|---|---|
| Minimum self-bond | 1M FLR |
| Minimum delegation | 50K FLR |
| Minimum self-bond duration | 2 months |
| Minimum delegation duration | 2 weeks |
| Delegation factor | 15x |
| Maximum total stake | 200M FLR |
| Max validators per entity | 4 |
Once self-bond amount and expiry are submitted, they are locked until expiry. Choose the duration deliberately.
Step 8: Register Validator Node ID with EntityManager
After FSP identity registration is complete, link your validator NodeID to the Entity Identity address.
Prepare values:
PATH_TO_CRT=/data/flare/node/staking/staker.crt
PATH_TO_KEY=/data/flare/node/staking/staker.key
ZERO_PREFIX=0000000000000000000000000000000000000000000000000000000000000000
IDENTITY_ADDRESS=your_identity_address_without_0x
Generate _nodeId:
cat $PATH_TO_CRT | tail -n +2 | head -n -1 \
| base64 -d \
| openssl dgst -sha256 -binary \
| openssl rmd160 -provider legacy -binary \
| xxd -p \
| sed -e 's/^/0x/;'
Generate _certificateRaw:
cat $PATH_TO_CRT | tail -n +2 | head -n -1 \
| base64 -d \
| xxd -p \
| tr -d '\n' \
| sed -e 's/^/0x/;' && echo
Generate _signature:
echo -n $ZERO_PREFIX$IDENTITY_ADDRESS \
| xxd -r -p \
| openssl dgst -sha256 -sign $PATH_TO_KEY \
| xxd -p \
| tr -d '\n' \
| sed -e 's/^/0x/;' && echo
Call EntityManager.registerNodeId(bytes20 _nodeId, bytes _certificateRaw, bytes _signature) from the Identity address.
Flare mainnet EntityManager:
0x134b3311C6BdeD895556807a30C7f047D99DfdC2
Step 9: Verify Validator Status
NODE_ID="NodeID-..."
curl --data '{
"jsonrpc": "2.0",
"method": "platform.getCurrentValidators",
"params": {
"nodeIDs": ["'"${NODE_ID}"'"]
},
"id": 1
}' -H 'content-type:application/json;' \
https://flare-api.flare.network/ext/P | jq
Check uptime, connected, and the returned validator weight fields. The official go-flare v1.13.0 release notes say platform.getCurrentValidators removed StakeAmount; use weight.