Backup and restore¶
This chapter gives a direct, staged procedure for recovering a Koinos node.
The public backup is useful for avoiding a full mainnet synchronization. It is not a replacement for your private configuration, peer identity, wallet, or producer-key backups.
The example paths below are:
/opt/koinos: the official deployment checkout;/var/lib/koinos: the active node data;/srv/koinos-restore: temporary download and extraction space.
Confirm your real paths in .env before running any command. Do not adapt this
procedure to another network.
What to back up privately¶
Keep separate recovery copies according to their sensitivity:
| Data | Typical location | Recovery purpose |
|---|---|---|
| deployment and configuration | checkout, .env, config/ |
reproduce the reviewed node |
| producer and wallet keys | operator-defined key storage | recover authority |
| P2P identity | BASEDIR/p2p |
retain the peer identity |
| core public data | BASEDIR/chain, BASEDIR/block_store |
avoid a full synchronization |
| optional indexes | transaction, account, contract metadata stores | avoid index rebuild time |
Encrypt keys and identities before copying them off-host. Store the decryption secret separately and test a restoration in an isolated directory.
About the public mainnet backup¶
Verified on 2026-07-25, the Koinos Foundation seed host published:
koinos-backup.tar.gz;koinos-backup.tar.gz.metadata;koinos-backup.tar.gz.sha256.
The observed metadata dated the snapshot 2026-07-19 02:39:13 UTC and reported approximately 57 GB compressed. Always open the current backup directory and read the current metadata before downloading. The filename, size, date, checksum, and layout can change.
Do not extract the archive directly into /
The published metadata currently shows a direct extraction command. Do
not use it. First verify the checksum and archive paths, extract into a
staging directory, and install only chain and block_store.
1. Prepare enough space¶
You need room for:
- the compressed archive;
- the extracted
chainandblock_store; - the previous local data retained for rollback.
Check both the active data filesystem and staging filesystem:
df -h /var/lib/koinos /srv
du -sh /var/lib/koinos
Create a staging directory owned by the node operator:
sudo install -d -m 750 -o koinos -g koinos /srv/koinos-restore
cd /srv/koinos-restore
Replace koinos with the real operator account.
2. Download the metadata and backup¶
Download the three current files directly from the Foundation seed:
curl --fail --location --remote-name \
https://seed.koinosfoundation.org/backups/koinos-backup.tar.gz.metadata
curl --fail --location --remote-name \
https://seed.koinosfoundation.org/backups/koinos-backup.tar.gz.sha256
curl --fail --location --continue-at - --remote-name \
https://seed.koinosfoundation.org/backups/koinos-backup.tar.gz
--continue-at - allows curl to resume an interrupted large download.
Read the metadata before continuing:
less koinos-backup.tar.gz.metadata
Stop if it does not describe the intended mainnet backup or if you cannot provide the required free space.
3. Verify the download and archive paths¶
Extract the published digest and make sha256sum verify the local filename:
published_sha="$(awk 'NR == 1 {print $1}' \
koinos-backup.tar.gz.sha256)"
[[ "$published_sha" =~ ^[0-9a-fA-F]{64}$ ]]
printf '%s %s\n' "$published_sha" koinos-backup.tar.gz |
sha256sum --check -
Expect koinos-backup.tar.gz: OK. The conversion is necessary because the
published checksum currently contains the seed host's absolute source path.
Write the archive member names without extracting anything:
tar -tzf koinos-backup.tar.gz > archive-members.txt
test -s archive-members.txt
Reject absolute paths, parent traversal, and link entries automatically, then require the two public state directories:
(
set -euo pipefail
if LC_ALL=C grep -Eq '(^/|(^|/)\.\.(/|$))' archive-members.txt; then
printf 'ERROR: unsafe archive member path\n' >&2
exit 1
fi
if tar -tvzf koinos-backup.tar.gz |
awk 'substr($1, 1, 1) == "l" || substr($1, 1, 1) == "h" { found=1 }
END { exit !found }'
then
printf 'ERROR: archive contains link entries\n' >&2
exit 1
fi
grep -q '^\.koinos/chain/' archive-members.txt
grep -q '^\.koinos/block_store/' archive-members.txt
)
Review the bounded beginning and end of the accepted listing:
sed -n '1,40p' archive-members.txt
tail -n 40 archive-members.txt
If the current archive uses a different layout, stop and review the procedure instead of guessing new extraction paths.
4. Stop the node and preserve local state¶
Before stopping, reject an unexpected target and verify that the running node and the trusted public endpoint have the same chain ID:
(
set -euo pipefail
koinos_basedir=/var/lib/koinos
restore_stage=/srv/koinos-restore
case "$koinos_basedir" in
""|/|/home|/var|/var/lib) exit 1 ;;
esac
test -d "$koinos_basedir"
test -d "$restore_stage"
local_chain_id="$(curl --fail --silent --show-error \
http://127.0.0.1:8080/ \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","method":"chain.get_chain_id","params":{},"id":1}' |
jq -er '.result.chain_id')"
mainnet_chain_id="$(curl --fail --silent --show-error \
https://api.koinos.io/jsonrpc \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","method":"chain.get_chain_id","params":{},"id":1}' |
jq -er '.result.chain_id')"
printf 'local chain ID: %s\n' "$local_chain_id"
printf 'mainnet chain ID: %s\n' "$mainnet_chain_id"
test "$local_chain_id" = "$mainnet_chain_id"
)
From the official checkout, stop the node cleanly:
cd /opt/koinos
docker compose stop
docker compose ps
Wait until no Koinos service is running.
Create and record a unique rollback directory:
rollback_dir="/var/lib/koinos-before-restore-$(date -u +%Y%m%dT%H%M%SZ)"
sudo install -d -m 750 -o koinos -g koinos "$rollback_dir"
printf '%s\n' "$rollback_dir" \
> /srv/koinos-restore/rollback-directory.txt
Display the target and stop if it is not exactly the new directory just created:
rollback_dir="$(cat /srv/koinos-restore/rollback-directory.txt)"
printf 'active data: %s\nrollback data: %s\n' \
/var/lib/koinos "$rollback_dir"
test -d "$rollback_dir"
test ! -e "$rollback_dir/chain"
test ! -e "$rollback_dir/block_store"
Move current public and rebuildable state there:
rollback_dir="$(cat /srv/koinos-restore/rollback-directory.txt)"
for state_dir in \
chain block_store mempool transaction_store account_history contract_meta_store
do
if sudo test -e "/var/lib/koinos/$state_dir"; then
sudo mv "/var/lib/koinos/$state_dir" "$rollback_dir/"
fi
done
Do not move or replace:
.envor the deployment checkout;config/;- the local
p2pdirectory; - wallets or producer keys.
5. Extract only the core public data¶
Return to the staging directory and create an empty extraction target:
cd /srv/koinos-restore
mkdir extracted
Extract only the two paths confirmed in the listing:
tar -xzf koinos-backup.tar.gz -C extracted \
.koinos/chain .koinos/block_store
Copy the staged core data into the active basedir:
sudo cp -a extracted/.koinos/chain /var/lib/koinos/
sudo cp -a extracted/.koinos/block_store /var/lib/koinos/
sudo chown -R --reference=/var/lib/koinos \
/var/lib/koinos/chain /var/lib/koinos/block_store
Before startup, require chain.verify-blocks: true in the active configuration:
chain_section="$(sed -n '/^chain:/,/^[^[:space:]#]/p' \
/opt/koinos/config/config.yml)"
printf '%s\n' "$chain_section"
printf '%s\n' "$chain_section" |
grep -Eq '^[[:space:]]+verify-blocks:[[:space:]]*true([[:space:]]|$)'
The command fails if the displayed chain section does not explicitly set
verify-blocks: true. Keep the active mainnet genesis data, descriptors, peer
identity, and image versions from your selected release or commit and its
configuration files.
6. Start and validate¶
Start the same profiles that were active before the restore:
cd /opt/koinos
docker compose up -d
docker compose ps
docker compose logs --tail 100 --follow chain block_store p2p
Do not remove the rollback directory yet. Confirm:
- every expected container remains running;
- the local chain ID is mainnet;
- block verification reports no errors;
- the head advances and becomes recent;
- peers and gossip are active;
- disk space remains safe;
- any enabled JSON-RPC, REST, or gRPC endpoint responds normally.
Optional index services will rebuild their local data because this procedure
installs only chain and block_store.
Roll back¶
If validation fails:
Stop the node and move both generations directly:
cd /opt/koinos
docker compose stop
rollback_dir="$(cat /srv/koinos-restore/rollback-directory.txt)"
failed_restore="/var/lib/koinos-failed-restore-$(date -u +%Y%m%dT%H%M%SZ)"
sudo install -d -m 750 -o koinos -g koinos "$failed_restore"
for state_dir in \
chain block_store mempool transaction_store account_history contract_meta_store
do
if sudo test -e "/var/lib/koinos/$state_dir"; then
sudo mv "/var/lib/koinos/$state_dir" "$failed_restore/"
fi
if sudo test -e "$rollback_dir/$state_dir"; then
sudo mv "$rollback_dir/$state_dir" /var/lib/koinos/
fi
done
docker compose config
docker compose up -d
docker compose ps
Run the same chain-ID, head-freshness, advancement, gossip, peer, API, and disk checks used after the restore.
Do not delete either generation until the recovered node has remained healthy.
The current public testnet has query endpoints but no verified public external-operator bundle. Do not substitute testnet or Harbinger files into this mainnet procedure.