Category: Tech Tutorials

  • Ethereum Solo-Staking on Proxmox

    Ethereum Solo-Staking on Proxmox

    Setting up an Ethereum node requires careful consideration of system resources and containerization strategies, and requires a little more configuration than normal when trying to set up on a Proxmox server. In this guide, we’ll walk through the process of running eth-docker within a LXC on Proxmox.

    This is not for the faint of heart. We assume you have Docker experience, especially since we are making somewhat major modifications to eth-docker.

    High-level Overview of Architecture

    this method has been blessed by /u/yorickdowne, Staking Educator of /r/ethstakers

    Before diving into the setup, let’s go over the game plan. Note the “nesting”

    1. Proxmox as the hypervisor running on bare-metal
      • LXC running within Proxmox
        • Docker containers managed by eth-docker running inside the LXC

    leading to…

    Hardware Prerequisites

    • Quad Core CPU
    • 4TB “mainstream” SSD – TLC and DRAM, formatted in ext4
    • 32 GiB of RAM – 16 GiB works but can be challenging depending on client mix

    As noted on the eth-docker documentation, you might be able to get away with smaller SSD and less RAM. However, you’re about to stake 32 Eth which at today’s market value is almost $90K USD. You’re not hurting for the $300 to get an enterprise grade 4TB SSD (at least that’s what I told myself to justify the purchase).

    Configuring the LXC Container

    When setting up an LXC from Proxmox, my go-to is the Proxmox VE Helper-Scripts (I may be slightly biased as I am part of the Proxmox Helper Scripts org). From your host shell, grab the Docker LXC

    bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/docker.sh)"

    When setting up, make sure to give the LXC 4 cores and 32GB RAM!

    Let’s make sure the SSD is mounted to the LXC. Navigate to /etc/pve/lxc on the host machine and vi <lxc>.conf

    ...
    hostname: eth-docker
    memory: 32768
    mp0: /mnt/ethchain,mp=/mnt/ethchain
    ...

    Now we’ve set up the LXC, let’s go to the LXC shell and start setting things up from there

    Setting up eth-docker

    From here, you can follow the eth-docker quickstart:

    cd ~ && git clone https://github.com/eth-educators/eth-docker.git && cd eth-docker
    
    # Install pre-requisites such as Docker
    
    ./ethd install
    
    # Configure Eth Docker - have an Ethereum address handy where you want Execution Layer rewards to go
    
    ./ethd config

    For config, you can start with the testnet, and select Ethereum node. I chose to use Prysm consensus client and Geth execution client. For testing, MEV boost does not matter, but when reconfiguring for mainnet, you should opt for it.

    After configuring, don’t run./ethd up just yet. This next step is the secret sauce for utilizing our SSD.

    Volume Override to SSD

    We want to create an override .yaml file that maps the volume from our host machine to the SSD.

    my-volumes.override.yml:

    services:
      ######################################################
      # Geth (execution)
    ######################################################
    
      execution:
        volumes:
          # Geth chain data (instead of named volumes geth-el-data / geth-eth1-data):
          - "${GETH_ETH1DATA_PATH}:/var/lib/goethereum"
          - "${GETH_DATA_PATH}:/var/lib/geth"
    
          # The JWT secret is usually shared with the consensus client for Engine API authentication.
          # Keep referencing a Docker volume if you like, or use a direct host path:
          - "jwtsecret:/var/lib/geth/ee-secret"
    
          # Localtime (optional)
          - "/etc/localtime:/etc/localtime:ro"
    
      ######################################################
      # Prysm: beacon (consensus) client ######################################################
    
      consensus:
        volumes:
          # By default, prysm.yml uses prysmbeacon-data -> /var/lib/prysm-og
          # and prysmconsensus-data -> /var/lib/prysm
          - "${PRYSM_BEACON_PATH}:/var/lib/prysm-og"
          - "${PRYSM_CONSENSUS_PATH}:/var/lib/prysm"
    
          # The beacon client needs the JWT secret to talk to Geth:
          - "jwtsecret:/var/lib/prysm/ee-secret"
    
          - "/etc/localtime:/etc/localtime:ro"
    
      ######################################################
      # Prysm: validator client
    ######################################################
    
      validator:
        volumes:
          # The validator’s data: typically prysmvalidator-data -> /var/lib/prysm
          - "${PRYSM_VALIDATOR_PATH}:/var/lib/prysm"
    
          # Usually the validator does NOT need the JWT secret. 
          # If you have a specialized setup (e.g., external builder), you might do it differently.
          # - "jwtsecret:/var/lib/prysm/ee-secret"
    
          - "/etc/localtime:/etc/localtime:ro"

    Save this file, and now go to your .env and modify the COMPOSE_FILE line in your .env

    # The settings for eth-docker are in .env, use "nano .env". Don't edit default.env itself.
    # Client choice: See https://eth-docker.net/Usage/Advanced for available options
    COMPOSE_FILE=prysm.yml:geth.yml:grafana.yml:grafana-shared.yml:mev-boost.yml:my-volumes.override.yml:deposit-cli.yml:prysm-web-shared.yml
    ...

    We also want to add the override paths to our .env. I suggest you add them to the end of the .env file

    # Prysm volumes
    PRYSM_BEACON_PATH=/mnt/ethchain/prysm/beacon
    PRYSM_CONSENSUS_PATH=/mnt/ethchain/prysm/consensus
    PRYSM_VALIDATOR_PATH=/mnt/ethchain/prysm/validator
    
    # Geth volumes
    GETH_DATA_PATH=/mnt/ethchain/geth/data
    GETH_ETH1DATA_PATH=/mnt/ethchain/geth/eth1data

    Now, we can finally start the stack

    ./ethd up

    Importing Validator Keys

    At this point, our node is up and the consensus and execution layer should be syncing. With a good internet connection, expect this to take several hours to an entire day, so don’t fret if it seems to be syncing forever.

    From here, follow the Eth Docker Docs for key creation.

    I did personally run into an issue with using the keymanager API. As noted by the docs:

    If you use the Prysm Web, you can use it or this command-line process to import keys.

    As seen in the .env, we have enabled Prysm Web so we can bypass the keymanager API. This is where you want to import the keystore-xxxxxxxx.json that was generated when you create the keys.

    Deposit at launchpad

    I think this part deserves its own section. It’s honestly pretty nerve-wracking to send 32 Eth and the Mainnet launchpad honestly sucks, but following the steps does get you there. I refreshed the page after depositing and it put me back to the start of the launchpad, which was not ideal. At any rate, after depositing, you can check the status of your deposit on the Prysm Web UI

    Once it makes it past the Consensus Layer, pop the champagne as you just set up a validator node! 🍾

    After-party and Security Notes

    Remember to:

    • Keep your system updated regularly
    • Use strong passwords for all services
    • Consider implementing additional firewall rules, as you should have completed in the Validator Checklist
    • Regularly backup your validator keys and wallet information

    Conclusion

    Running eth-docker in a Proxmox LXC container provides a flexible and maintainable environment for your Ethereum node. This setup offers good isolation while maintaining performance and allowing for easy backups and migrations.

    As recommended by the Mainnet Launchpad checklists, join the Discord communities for your consensus and execution clients, and check the eth-docker GitHub repository for updates and best practices.

    Thanks for reading!