Manual Node Setup
This guide is for advanced users. If you are not sure why you want a manual setup, use the automated SSV Stack setup.
Pre-requisites
1. Enable SSH
You need SSH access to your server:
How to SSH into a machine
See the EthStaker guide: https://docs.ethstaker.cc/ethstaker-knowledge-base/tutorials/connect-via-ssh
If you are using a cloud server, follow your provider's documentation. For example, AWS: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-linux-inst-ssh.html
2. Install Docker
Docker
Follow the official Docker documentation for the option that matches your server.
Docker usually requires sudo. If you want to avoid using it every time, you can grant the required permissions once: https://stackoverflow.com/questions/48957195/how-to-fix-docker-got-permission-denied-issue
3. Install Git
Git
On Debian or Ubuntu, run apt-get install git.
For other Operating Systems, see the official Git documentation.
4. Install Golang (optional)
Golang
If you want to build from source, install Go first.
For details, see the official Go installation instructions.
Generate Operator Keys (Encrypted)
The safest way to run your Operator node is with an encrypted key pair. This encrypts your Public Key (PK) and Secret Key (SK) with a password you choose.
Password file
Create a file named password with the password you want to use for your Secret Key:
echo YOUR_PASSWORD >> passwordKey pair generation and encryption
- docker run
- Build from source
Use the node Docker image to generate and encrypt the keys. Replace ./path_to_password with the real path to your password file:
docker run --name ssv-node-key-generation -v ./path_to_password:/password -it "ssvlabs/ssv-node:latest" /go/bin/ssvnode generate-operator-keys --password-file=password && docker cp ssv-node-key-generation:/encrypted_private_key.json ./encrypted_private_key.json && docker rm ssv-node-key-generationThis requires go version 1.22 on the system. make is optional if you prefer to run the equivalent command from the Makefile.
Clone repository
Clone the ssv repository locally:
git clone git@github.com:ssvlabs/ssv.git
Build
From the project root, run:
make build
Generate keys
Use the binary to generate and encrypt the keys. Replace ./path_to_password with the real path to your password file:
./bin/ssvnode generate-operator-keys --password-file=./path_to_passwordBack up encrypted_private_key.json and password on a separate device. If either file is lost, you will permanently lose access to your Operator.
Create Configuration File
Copy the config.yaml example below and replace the placeholders with your real values. The essential fields are editable.
Make sure your ETH1Addr endpoint uses WebSocket, not HTTP.
global:# Console output log levelLogLevel: info
# Debug logs file pathLogFilePath: ./data/debug.log
# Number of log files preserved, 500MB each (time duration depends on number of validators and other factors).# Roughly equates to half a day.# Increase if you want to preserve log files for longer. This would require more disk spaceLogFileBackups: 10
db:# Path to a persistent directory to store the node's database.Path: ./data/db
ssv:# The SSV network to join to# Available options are mainnet and hoodiNetwork: mainnet
ValidatorOptions: # Block proposals are by default controlled by Beacon Node. # Requires the connected Beacon node to be MEV-enabled. # Please see https://docs.ssv.network/operators/operator-node/setup-sidecars/configuring-mev
eth2:# HTTP URL of the Beacon node to connect to.# If you want to use multiple endpoints you can divide them with ;# e.g. http://example.url:5052;http://example.url:5053BeaconNodeAddr: http://example.url:5052
# Both enable improved attestation accuracy from multiple Beacon nodes.# Will have no effect with only 1 endpoint.WithWeightedAttestationData: falseWithParallelSubmissions: false
eth1:# WebSocket URL of the Eth1 node to connect to.# If you want to use multiple endpoints you can divide them with ;# e.g. ws://example.url:8546/ws;ws://example.url:8547/wsETH1Addr: ws://example.url:8546/ws
p2p:# Optionally provide the external IP address of the node, if it cannot be automatically determined.# HostAddress: 192.168.1.1
# Optionally override the default TCP & UDP ports of the node.# TcpPort: 13001# UdpPort: 12001
KeyStore:PrivateKeyFile: ./encrypted_private_key.jsonPasswordFile: ./password
# Enables Doppelganger Protection for validators, see https://github.com/ssvlabs/ssv/blob/v2.3.0/doppelganger/README.mdEnableDoppelgangerProtection: false
# This enables monitoring at the specified port, see https://docs.ssv.network/operators/operator-node/monitoring/MetricsAPIPort: 15000# This enables node health endpoint for troubleshooting, see https://docs.ssv.network/operators/operator-node/maintenance/troubleshootingSSVAPIPort: 16000Start the Node
Do not run multiple SSV Node instances with the same Operator keys.
This does not improve resiliency and could lead to validator slashing.
- docker compose
- docker run
- Build from source
Example docker-compose.yml:
services: ssv: image: ssvlabs/ssv-node:latest ports: - 13001:13001 - 12001:12001/udp - 15000:15000 - 16000:16000 command: make BUILD_PATH="/go/bin/ssvnode" start-node volumes: - ./config.yaml:/config/config.yaml - ./data:/data - ./password:/password - ./encrypted_private_key.json:/encrypted_private_key.json environment: - CONFIG_PATH=/config/config.yaml container_name: ssv_node restart: unless-stopped networks: - ssv
networks: ssv: name: ssv driver: bridgeThen run docker compose up from the same directory as docker-compose.yml.
- This keeps the terminal attached so you can review logs during startup.
- If everything looks good, use
docker compose up -dto run in the background.
To start the node with Docker directly, run this from the directory that contains config.yaml. The command assumes the other required files are in the same directory:
docker run --restart unless-stopped --name ssv_node -e \
CONFIG_PATH=/config.yaml \
-p 13001:13001 -p 12001:12001/udp -p 15000:15000 -p 16000:16000 \
-v "$(pwd)/config.yaml":/config.yaml \
-v "$(pwd)":/data \
-v "$(pwd)/password":/password \
-v "$(pwd)/encrypted_private_key.json":/encrypted_private_key.json \
-it "ssvlabs/ssv-node:latest" make BUILD_PATH="/go/bin/ssvnode" start-node
- This keeps the terminal attached so you can review logs during startup.
- If the node is running correctly, add
-dafterdocker runto run it in the background.
If you already created the Operator keys with the compiled binary, you can start the node. Otherwise, build from source first.
This requires go version 1.22 on the system. make is optional if you prefer to run the equivalent command from the Makefile.
Clone repository
Clone the ssv repository locally:
git clone git@github.com:ssvlabs/ssv.git
Choose the version
List the available versions from the project root:
git tag
Replace v1.2.3 with the version you want to use. You can browse SSV Node releases here:
git checkout tags/v1.2.3Build
Build the selected version:
make build
Launch the node
Start the node:
./bin/ssvnode start-node
By default, the node looks for the config file at ./config/config.yaml. If your file is elsewhere, use the CONFIG_PATH environment variable to set a custom path.
You can also use the compiled binary with a systemd service.
Pay attention to the pubKey field. It contains the public key you need to register the Operator on SSV Network.
Peer-to-peer ports configuration and firewall
When configuring your firewall, open the same ports that you expose in the container command. By default these are 12001 UDP and 13001 TCP, plus 15000 TCP for metrics and 16000 TCP for the health endpoint.
If you change the default ports in config.yaml, update the container command as well. Changing only the host port mappings in Docker is not enough.
You can also set HostAddress in the config to the machine's public static IP address.
p2p: HostAddress: 1.2.3.4 UdpPort: 12001 TcpPort: 13001Database backups
SSV's database (db) is critical for slashing protection. If it is lost or corrupted and operation continues, it can lead to double-signing and severe penalties.
Implement a reliable backup and recovery strategy for your database. Operators are responsible for managing and protecting their own databases.
What's next?
- Configure MEV to increase rewards for block proposals.
- Enable DKG to improve your chances of joining more clusters.
- Use the monitoring stack to stay on top of performance.
- Check the troubleshooting page if you run into issues.