Skip to main content

Run with systemd

Linux only

systemd isn't available on Windows or macOS. Use Run with Docker Compose instead.

Network
Execution client
Engine API connection
What you want to run
Initial sync

The examples use this layout:

/usr/local/bin/ # beacon-chain
/opt/besu/ # Besu
/var/lib/ethereum/
├── jwt.hex # shared by the execution client and beacon node
├── execution/ # execution client data
└── beacon/ # beacon node data

Before you begin​

  • Prysm’s binaries are installed with the Binaries tab of Install Prysm.

Set up the services​

  1. Create one unprivileged user per process, the data directories, and the JWT secret. Only the execution client and beacon node can read the secret, through a shared ethereum group:

    # Create one system user per service: no password, no home folder, no login shell.
    # Each service runs as its own user.
    for u in execution beacon; do
    sudo useradd --system --no-create-home --shell /usr/sbin/nologin $u
    done

    # Create the data directories. Each one is readable and writable only by its service's user.
    sudo install -d -m 0755 /var/lib/ethereum
    sudo install -d -m 0700 -o execution -g execution /var/lib/ethereum/execution
    sudo install -d -m 0700 -o beacon -g beacon /var/lib/ethereum/beacon

    # Create an "ethereum" group with the execution client and beacon node in it.
    sudo groupadd --system ethereum
    sudo usermod -aG ethereum execution
    sudo usermod -aG ethereum beacon

    # Create the JWT secret: 32 random bytes, written as hex.
    # Only root can change it, and only the "ethereum" group can read it.
    openssl rand -hex 32 | tr -d "\n" | sudo tee /var/lib/ethereum/jwt.hex > /dev/null
    sudo chown root:ethereum /var/lib/ethereum/jwt.hex
    sudo chmod 0640 /var/lib/ethereum/jwt.hex
  2. Create the execution client service:

    /etc/systemd/system/execution.service
    [Unit]
    Description=Ethereum execution client
    Wants=network-online.target
    After=network-online.target

    [Service]
    User=execution
    Group=execution
    ExecStart=/opt/besu/bin/besu \
    --network=mainnet \
    --data-path=/var/lib/ethereum/execution \
    --engine-jwt-secret=/var/lib/ethereum/jwt.hex
    Restart=on-failure
    RestartSec=5
    TimeoutStopSec=600
    NoNewPrivileges=true
    ProtectSystem=strict
    ReadWritePaths=/var/lib/ethereum/execution
    ProtectHome=true
    PrivateTmp=true

    [Install]
    WantedBy=multi-user.target
  3. Create the beacon node service:

    /etc/systemd/system/beacon.service
    [Unit]
    Description=Prysm beacon node
    Wants=network-online.target execution.service
    After=network-online.target execution.service

    [Service]
    User=beacon
    Group=beacon
    ExecStart=/usr/local/bin/beacon-chain \
    --mainnet \
    --datadir=/var/lib/ethereum/beacon \
    --execution-endpoint=http://127.0.0.1:8551 \
    --jwt-secret=/var/lib/ethereum/jwt.hex \
    --checkpoint-sync-url=https://sync-mainnet.beaconcha.in \
    --beacon-db-pruning \
    --disable-log-colors \
    --accept-terms-of-use
    Restart=on-failure
    RestartSec=5
    TimeoutStopSec=120
    NoNewPrivileges=true
    ProtectSystem=strict
    ReadWritePaths=/var/lib/ethereum/beacon
    ProtectHome=true
    PrivateTmp=true

    [Install]
    WantedBy=multi-user.target

    https://sync-mainnet.beaconcha.in is one of several community checkpoint sync endpoints; any one you trust works.

    --beacon-db-pruning deletes blocks and states older than about 5 months, the oldest data other nodes can still ask for, so the database stops growing. Leave it out if you need the full history.

    --accept-terms-of-use is needed because a service can't answer the first-run prompt.

  4. Start the services:

    # Make systemd read the unit files you just created.
    sudo systemctl daemon-reload

    # Start the services at every boot (enable), and right now (--now).
    # They start in the order set by the After= lines in the units.
    sudo systemctl enable --now execution beacon

    Restart=on-failure in each unit restarts the service after a crash.

    Check that they're running:

    systemctl is-active execution beacon

    Every service should be active.

    Each service logs to the journal. To follow one, run its line:

    sudo journalctl -fu execution # follow the execution client
    sudo journalctl -fu beacon # follow the beacon node

    Check the beacon node's sync status:

    curl -s http://127.0.0.1:3500/eth/v1/node/syncing

    The node is fully running once the response shows all three of these as false:

    {
    "data": {
    "head_slot": "…",
    "sync_distance": "0",
    "is_syncing": false,
    "is_optimistic": false,
    "el_offline": false
    }
    }
    • "el_offline": false: the beacon node reaches the execution client. This should be the case as soon as both services are up. If it stays true, read the execution client's logs:

      sudo journalctl -u execution -n 50 --no-pager
    • "is_syncing": false: the beacon node is synced.

      From a checkpoint, this takes a few minutes: the node starts from a recent finalized state instead of replaying the chain.

    • "is_optimistic": false: the execution client is synced. This takes the longest, from a few hours to a few days depending on your execution client and the network. Until then, the beacon node follows the chain but can't check the blocks’ transactions.

After you edit a unit, run this before restarting it:

sudo systemctl daemon-reload

If you move a data directory, update ReadWritePaths= too, or the service fails with read-only file system.

Logs. To look back through a service's logs, filter by time or by level:

sudo journalctl -u beacon --since "1 hour ago" # the last hour
sudo journalctl -u beacon -p warning -b # warnings and errors since boot

The journal rotates by itself. To cap its size, set SystemMaxUse=2G in /etc/systemd/journald.conf and run:

sudo systemctl restart systemd-journald

Prysm also keeps the most recent debug logs in <datadir>/logs/: the current file plus one older one, at most about 500 MB. To turn that off, add --disable-ephemeral-log-file.

Check that it works​

Restart the machine once, then run the checks from Start the services again: everything should come back by itself.

Troubleshooting​

status=217/USER. The User= in the unit doesn't exist. Create it as in step 1.

permission denied reading jwt.hex. The service user isn't in the ethereum group, or the file isn't root:ethereum 0640. Test with:

sudo -u beacon cat /var/lib/ethereum/jwt.hex

permission denied or read-only file system in the data directory. The directory belongs to another user, often after running a binary by hand as root. Fix it:

sudo chown -R beacon:beacon /var/lib/ethereum/beacon

Also check that ReadWritePaths= in the unit points to the data directory.

The service restarts in a loop. Read the last error:

sudo journalctl -u beacon -n 50 --no-pager

A misspelled or removed flag stops Prysm at startup; compare with the beacon-chain reference.

Remove everything​

These commands undo this page.

# Stop the services, and stop them from starting at boot.
sudo systemctl disable --now execution beacon

Then delete the rest:

# Delete the unit files, and make systemd forget them.
sudo rm -f /etc/systemd/system/execution.service
sudo rm -f /etc/systemd/system/beacon.service
sudo systemctl daemon-reload
sudo systemctl reset-failed

# Delete all the data: chain data, JWT secret.
sudo rm -r /var/lib/ethereum

# Delete the system users and the "ethereum" group.
sudo userdel execution
sudo userdel beacon
sudo groupdel ethereum

The binaries in /usr/local/bin and the client’s folder in /opt remain; delete them yourself if you no longer need them.