II-1 Folders and configuration
A system user for the node, config in /etc/cardano, data in /var/lib/cardano.
All nodessudo useradd -r -m -d /var/lib/cardano -s /sbin/nologin cardano
sudo mkdir -p /etc/cardano /var/lib/cardano/db
sudo cp ~/.local/share/mainnet/*.json /etc/cardano/
sudo chown -R cardano:cardano /etc/cardano /var/lib/cardano
sudo usermod -aG cardano $USER
Log out and in again. The block producer shares no peers:
Block producersudo jq '.PeerSharing = false' /etc/cardano/config.json > /tmp/config.json
sudo install -o cardano -g cardano -m 644 /tmp/config.json /etc/cardano/config.json
Next: Download the chain with Mithril →
II-2 Download the chain with Mithril
A certified snapshot: hours instead of days.
All nodescurl --proto '=https' --tlsv1.2 -sSfL \
https://raw.githubusercontent.com/IntersectMBO/mithril/refs/heads/main/mithril-install.sh \
| sh -s -- -c mithril-client -d latest -p $HOME/.local/bin
export AGGREGATOR_ENDPOINT=https://aggregator.release-mainnet.api.mithril.network/aggregator
export GENESIS_VERIFICATION_KEY=$(wget -q -O - \
https://raw.githubusercontent.com/IntersectMBO/mithril/main/mithril-infra/configuration/release-mainnet/genesis.vkey)
export ANCILLARY_VERIFICATION_KEY=$(wget -q -O - \
https://raw.githubusercontent.com/IntersectMBO/mithril/main/mithril-infra/configuration/release-mainnet/ancillary.vkey)
mkdir -p ~/mithril && cd ~/mithril
~/.local/bin/mithril-client cardano-db download latest --include-ancillary
sudo rm -rf /var/lib/cardano/db
sudo mv ~/mithril/db /var/lib/cardano/db
sudo chown -R cardano:cardano /var/lib/cardano/db
Note The client checks the snapshot's certificate chain against the genesis key — a tampered snapshot fails. GitHub rate limit? Take mithril-client from the Mithril releases.
Next: Topology →
II-3 Topology
Relays talk to the network and your block producer; the block producer only to your relays.
Relay — /etc/cardano/topology.json:
File{
"bootstrapPeers": [
{ "address": "backbone.cardano.iog.io", "port": 3001 },
{ "address": "backbone.mainnet.cardanofoundation.org", "port": 3001 }
],
"localRoots": [
{
"accessPoints": [
{ "address": "<block-producer-ip>", "port": 6000 }
],
"advertise": false,
"trustable": true,
"valency": 1
}
],
"peerSnapshotFile": "peer-snapshot.json",
"publicRoots": [
{ "accessPoints": [], "advertise": false }
],
"useLedgerAfterSlot": 194140785
}
Block producer — /etc/cardano/topology.json:
File{
"bootstrapPeers": [],
"localRoots": [
{
"accessPoints": [
{ "address": "<relay-1-ip>", "port": 6000 },
{ "address": "<relay-2-ip>", "port": 6000 },
{ "address": "<relay-3-ip>", "port": 6000 }
],
"advertise": false,
"trustable": true,
"valency": 3
}
],
"publicRoots": [],
"useLedgerAfterSlot": -1
}
Take useLedgerAfterSlot for the relays from your release's topology file. Reload without restart:
Block producer or relaysudo systemctl reload cardano-node
Next: The air-gapped machine →
II-4 The air-gapped machine
A computer that never connects — for the cold keys and every signature.
A spare laptop with fresh Ubuntu. After installing: Wi-Fi and Bluetooth off for good, no cable. Bring the checked node archive on a USB stick:
Air-gapped machinecd /media/$USER/<usb-stick>
sha256sum --ignore-missing -c cardano-node-11.1.3-sha256sums.txt
mkdir -p ~/cardano && tar -xzf cardano-node-11.1.3-linux-amd64.tar.gz -C ~/cardano
sudo install -m 755 ~/cardano/bin/cardano-cli /usr/local/bin/
cardano-cli --version
mkdir -p ~/cold-keys && chmod 700 ~/cold-keys
Important Two encrypted backups of ~/cold-keys, in two places, restore-tested. Whoever holds these files owns the pool.
Next: Run the node as a service →
II-5 Run the node as a service
systemd starts it at boot and restarts it when it stops.
/etc/systemd/system/cardano-node.service on a relay:
File[Unit]
Description=Cardano Node
Wants=network-online.target
After=network-online.target
[Service]
User=cardano
Group=cardano
Type=simple
WorkingDirectory=/var/lib/cardano
ExecStart=/usr/local/bin/cardano-node run \
--config /etc/cardano/config.json \
--topology /etc/cardano/topology.json \
--database-path /var/lib/cardano/db \
--socket-path /run/cardano/node.socket \
--host-addr 0.0.0.0 \
--port 6000
ExecReload=pkill -HUP cardano-node
KillSignal=SIGINT
RestartKillSignal=SIGINT
TimeoutStopSec=300
LimitNOFILE=131072
Restart=always
RestartSec=5
SyslogIdentifier=cardano-node
RuntimeDirectory=cardano
RuntimeDirectoryMode=0750
[Install]
WantedBy=multi-user.target
On the block producer, ExecStart also names the pool files (from Part III, step 3):
FileExecStart=/usr/local/bin/cardano-node run \
--config /etc/cardano/config.json \
--topology /etc/cardano/topology.json \
--database-path /var/lib/cardano/db \
--socket-path /run/cardano/node.socket \
--host-addr 0.0.0.0 \
--port 6000 \
--shelley-kes-key /var/lib/cardano/keys/kes.skey \
--shelley-vrf-key /var/lib/cardano/keys/vrf.skey \
--shelley-operational-certificate /var/lib/cardano/keys/node.cert
All nodessudo systemctl daemon-reload
sudo systemctl enable --now cardano-node
journalctl -fu cardano-node
Check cardano-cli latest query tip shows "syncProgress": "100.00" before you go on.
Sources and license
Text, pictures and order are BRIAN's. Commands for system setup, the firewall, Mithril and the service file are adapted from the Cardano Developer Portal; every cardano-cli command was written for and run against cardano-cli 11.2.3. The node's own documentation always takes precedence.
Developer Portal license (MIT) — Copyright (c) 2021 Cardano Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.