Move to a new machine
Moving validators is safe if you follow one rule: the same key must never run in multiple validator clients, not even for a second. Prepare the new machine first, so your validators are offline only for the wait you choose (at least two epochs, about 13 minutes). A few missed attestations cost very little; a slashing costs far more.
Never start the new validator "just before" stopping the old one, and never run a failover copy. Most slashings happen exactly this way. See Avoid slashing.
The commands below use the users and paths from Run with systemd.
The commands below use the services and paths from Run with Docker Compose. Run them from the folder that holds docker-compose.yml.
On Windows, run them in your WSL terminal.
Before you begin
- The new machine meets the system requirements and has Prysm and an execution client installed.
- Access to the keys on the old machine, or the original keystores and their password.
-
- Your validator indices or public keys so that you can check them on a block explorer.
Move your validators
-
Sync the new node while the old one keeps validating. Start the execution client and beacon node on the new machine with checkpoint sync, without a validator client and without keys. Wait until Is my node healthy? shows it synced.
-
Stop and disable the old validator, so nothing restarts it:
sudo systemctl disable --now validatordocker compose stop validatordocker compose rm -f validatordocker compose upwould create it again, so don't run it until you remove the validator service in step 5.Stop the validator client with Ctrl+C in its terminal.
- Remove whatever starts it automatically, such as a cron job, a
tmuxsession, or a script.
Remove whatever starts automatically, such as a scheduled task or a startup script.
The old beacon node can keep running; it holds no keys.
- Remove whatever starts it automatically, such as a cron job, a
-
Check that the old validator is really off. Don't continue until all of these pass:
-
No process runs: this prints nothing:
pgrep -af 'validator|prysm'
- No process runs: Task Manager shows no
validatororprysmprocess.
-
No container runs: this shows no validator container, running or stopped:
docker ps -a
-
Nothing will restart it: this prints
disabled:systemctl is-enabled validatorNo cron job or script starts it either.
- Nothing will restart it: no cron job or script runs
docker compose up.
- Nothing will restart it: no cron job,
tmuxsession, or script starts it.
- Nothing will restart it: Task Scheduler and the Startup folder have nothing that starts it.
- If in doubt, unplug it. A machine you can't reach is a machine you can't prove is off.
-
-
Export slashing protection from the old machine, now that it has stopped signing:
sudo install -d -m 0700 -o validator -g validator /var/lib/ethereum/validator/exportsudo -u validator /usr/local/bin/validator slashing-protection-history export \--datadir=/var/lib/ethereum/validator \--slashing-protection-export-dir=/var/lib/ethereum/validator/exportThis writes
/var/lib/ethereum/validator/export/slashing_protection.json.docker compose run --rm --no-deps validator slashing-protection-history export \--datadir=/data \--slashing-protection-export-dir=/data/export \--accept-terms-of-useThis writes
data/<NETWORK>/validator/export/slashing_protection.json../prysm.sh validator slashing-protection-history export \--datadir=<OLD_VALIDATOR_DATADIR> \--slashing-protection-export-dir=<EXPORT_DIR>This writes
<EXPORT_DIR>/slashing_protection.json..\prysm.bat validator slashing-protection-history export `--datadir=<OLD_VALIDATOR_DATADIR> `--slashing-protection-export-dir=<EXPORT_DIR>This writes
<EXPORT_DIR>\slashing_protection.json. -
Export the keys, then delete them from the old wallet. Use the original keystores, or export them to
backup.zipin the export directory:sudo -u validator /usr/local/bin/validator accounts backup \--wallet-dir=/var/lib/ethereum/validator/wallet \--wallet-password-file=/var/lib/ethereum/validator/wallet-password.txt \--backup-dir=/var/lib/ethereum/validator/exportsudo -u validator /usr/local/bin/validator accounts delete \--wallet-dir=/var/lib/ethereum/validator/wallet \--wallet-password-file=/var/lib/ethereum/validator/wallet-password.txtSelect the keys you are moving. Afterward, this must not show them:
sudo -u validator /usr/local/bin/validator accounts list \--wallet-dir=/var/lib/ethereum/validator/wallet \--wallet-password-file=/var/lib/ethereum/validator/wallet-password.txtdocker compose run --rm --no-deps validator accounts backup \--wallet-dir=/data/wallet \--wallet-password-file=/data/wallet-password.txt \--backup-dir=/data/export \--accept-terms-of-usedocker compose run --rm --no-deps validator accounts delete \--wallet-dir=/data/wallet \--wallet-password-file=/data/wallet-password.txt \--accept-terms-of-useSelect the keys you are moving. Afterward, this must not show them:
docker compose run --rm --no-deps validator accounts list \--wallet-dir=/data/wallet \--wallet-password-file=/data/wallet-password.txt \--accept-terms-of-useThen remove the
validatorservice fromdocker-compose.yml, sodocker compose upcan't start it again../prysm.sh validator accounts backup \--wallet-dir=<OLD_WALLET_DIR> \--backup-dir=<EXPORT_DIR>./prysm.sh validator accounts delete \--wallet-dir=<OLD_WALLET_DIR>Select the keys you are moving. Afterward, this must not show them:
./prysm.sh validator accounts list --wallet-dir=<OLD_WALLET_DIR>.\prysm.bat validator accounts backup `--wallet-dir=<OLD_WALLET_DIR> `--backup-dir=<EXPORT_DIR>.\prysm.bat validator accounts delete `--wallet-dir=<OLD_WALLET_DIR>Select the keys you are moving. Afterward, this must not show them:
.\prysm.bat validator accounts list --wallet-dir=<OLD_WALLET_DIR>Also delete the original keystore files from the old machine, and any VM snapshots or images that contain the keys: restoring one later would bring the validator back.
-
Copy the files to the new machine over an encrypted channel (
scp, an encrypted USB drive):slashing_protection.json, and the keystores orbackup.zip. Unzipbackup.zipinto a folder of its own on the new machine. Delete any intermediate copies. -
Wait at least two epochs (about 13 minutes) after the old validator stopped. Then look up your validators on a block explorer: the latest epochs must show missed attestations. If they show attestations after you stopped the old validator, something is still signing. Stop and find it.
-
Import slashing protection, then the keys, on the new machine with its validator stopped.
<PATH_TO_KEYSTORES>is the folder holding thekeystore-*.jsonfiles:sudo install -d -m 0700 -o validator -g validator /var/lib/ethereum/validator/importsudo cp <PATH_TO>/slashing_protection.json /var/lib/ethereum/validator/import/sudo cp -r <PATH_TO_KEYSTORES> /var/lib/ethereum/validator/import/keyssudo chown -R validator:validator /var/lib/ethereum/validator/importsudo -u validator /usr/local/bin/validator slashing-protection-history import \--datadir=/var/lib/ethereum/validator \--slashing-protection-json-file=/var/lib/ethereum/validator/import/slashing_protection.jsonsudo -u validator /usr/local/bin/validator accounts import \--keys-dir=/var/lib/ethereum/validator/import/keys \--wallet-dir=/var/lib/ethereum/validator/wallet \--wallet-password-file=/var/lib/ethereum/validator/wallet-password.txtsudo rm -r /var/lib/ethereum/validator/importdocker compose run --rm --no-deps \-v <PATH_TO>/slashing_protection.json:/import/slashing_protection.json:ro \validator slashing-protection-history import \--datadir=/data \--slashing-protection-json-file=/import/slashing_protection.json \--accept-terms-of-usedocker compose run --rm --no-deps -v <PATH_TO_KEYSTORES>:/keys:ro \validator accounts import \--keys-dir=/keys \--wallet-dir=/data/wallet \--wallet-password-file=/data/wallet-password.txt \--accept-terms-of-use./prysm.sh validator slashing-protection-history import \--datadir=<NEW_VALIDATOR_DATADIR> \--slashing-protection-json-file=<PATH_TO>/slashing_protection.json./prysm.sh validator accounts import \--keys-dir=<PATH_TO_KEYSTORES> \--wallet-dir=<NEW_WALLET_DIR>Use the same
--datadirthe validator will run with, or it starts with empty slashing protection..\prysm.bat validator slashing-protection-history import `--datadir=<NEW_VALIDATOR_DATADIR> `--slashing-protection-json-file=<PATH_TO>\slashing_protection.json.\prysm.bat validator accounts import `--keys-dir=<PATH_TO_KEYSTORES> `--wallet-dir=<NEW_WALLET_DIR>Use the same
--datadirthe validator will run with, or it starts with empty slashing protection. -
Start the new validator:
sudo systemctl enable --now validatorThe unit from Run with systemd already has your fee recipient, MEV-Boost settings and
--enable-doppelganger.docker compose up -dStart it with your fee recipient and MEV-Boost settings, and add
--enable-doppelgangerif your command doesn't have it.With doppelganger protection, before its first duty, the validator client asks the beacon node whether your keys attested in about the last two epochs. If they did, and its own slashing protection history shows no recent attestation for them, someone else signed: it exits instead of starting. It checks only once, so it's a last line of defense, not a replacement for step 7.
Check that it works
-
The new validator logs this for each key:
Validator activatedThen:
Submitted new attestations -
With doppelganger protection, it first logs:
Doppelganger check doneIf it exits with this instead, your keys are still active somewhere. Don't restart it: go back to step 3.
Duplicate instances exists in the network for validator keys -
A block explorer shows attestations again a few epochs after you started.
Follow the logs with:
sudo journalctl -fu validator
Follow the logs with:
docker compose logs -f validator
If the old machine is gone
If it died and you can't export slashing protection: make sure it can never come back online with the keys (wipe or destroy the disk), wait until a block explorer shows several epochs of missed attestations, then import the keys on the new machine without slashing protection.