Running SSV Node with SSL Configuration
Nexus Network uses SSV Network's Distributed Validator Technology (DVT) for node operations.
About ssv.network
ssv.network is a decentralized ETH staking network using Secret Shared Validator (SSV) technology, also known as Distributed Validator Technology (DVT).
Key Features
Active-Active Redundancy & Fault Tolerance
Non-Custodial & Secure ETH Staking
Decentralization & Diversity
Getting Started 🎯
In this section, we'll guide you through the initial steps to get started with node operators. Before you dive into the specifics, make sure you meet the system requirements and have everything in place.
System Requirements
Before installing, ensure that your system meets the following requirements:
Ubuntu 18.04 LTS or later (preferably)
8 cores
4GB RAM
20GB storage (10GB minimum)
IOPS > 10K
📌 The minimum system requirements above are for running only an SSV node. If you also plan to run the SSV node on the same machine as your Execution Client and/or Beacon Client, these requirements are in addition to your existing ones.
Ethereum Node Requirements:
Execution Client: Geth, you will see this node referenced as ETH1 in the SSV configuration
📌 An Execution Client (e.g., Geth) is responsible for handling transactions, executing smart contracts, and maintaining the state of the Ethereum blockchain. It processes all operations on the Ethereum network, including transaction validation and block creation.
Beacon Client: Prysm, you will see this node referenced as ETH2 in the SSV configuration
📌 A Beacon Client, such as Prysm, is responsible for maintaining the state of the Ethereum blockchain, validating transactions, and ensuring the network's security. It plays a crucial role in the consensus mechanism and overall operation of the Ethereum network.
We are now fully equipped to set up an SSV node. Setting up and running an SSV node involves five major steps. They are as follows:
Node setup
Enabling Maximal Extractable Value (Optional)
Setting up SSV-DKG
Updating Operator Metadata
Testing the Setup
NODE SETUP
📌 In this section, we'll guide you through the process of setting up your SSV node, including generating encrypted operator keys and creating the necessary configuration file. You'll learn how to deploy your node using Docker, ensuring secure and efficient operation. Follow these steps to establish and manage your node effectively.
Generate Operator Keys:
The most secure way to run your Operator node is to generate an encrypted key pair. This ensures that your Public Key (PK) and Secret Key (SK) are protected with your chosen password.
Password file
You will need to create a file (named `password` in this example) containing the password you chose for your Secret Key:
echo "<MY_OPERATOR_PASSWORD>" >> password
Key pair generation and encryption
This can be done in two ways.
1. Docker
2. Build from Source
We will be moving forward with Docker, if you want to try the other option, you can refer here.
Node Docker image will generate keys for you, then encrypt them with a password you provide, using the following command:
docker run --name ssv-node-key-generation -v <PATH_TO_PASSWORD_FILE>:/password
-it "bloxstaking/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-generation
Here is an example of the generated file.
{
"checksum": {
"function": "sha256",
"message": "affa5deb755d8ad13a039117dc6850d2a25ad62a870a1e1f8d4ef...",
"params": {}
},
"cipher": {
"function": "aes-128-ctr",
"message": "3022f3b5043b77eda7f336dd0218e6b7e633a3f42f7ae92ed9...",
"params": { "iv": "12e787716b0e3c30f2d68ed05464c16f" }
},
"kdf": {
"function": "pbkdf2",
"message": "",
"params": {
"c": 262144,
"dklen": 32,
"prf": "hmac-sha256",
"salt": "bc71d3213fe17f15879e6bc468b30eeeb2d0969176491d87f9b00a37bf314a4c"
}
},
"pubKey": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJak..."
}
❗ Pay close attention to the pubKey
field, as the name says, contains the public key, which is needed to register the Operator on the ssv.network. Please Note that it is still possible to use generated (unencrypted) keys, but as explained in the rest of the guide, encrypted keys should be considered the default and preferred option
Create Configuration file
Copy the following config.yaml
file, just be sure to replace all the placeholders (ETH2_NODE
, ETH1_WEBSOCKET_ADDRESS
etc.) with actual values.
In particular, substitute ENCRYPTED_PRIVATE_KEY_JSON
with the operator-encrypted private key file generated above (e.g. encrypted_private_key.json
) and PASSWORD_FILE
with the file containing the password used to generate the encrypted key itself.
❗ Change the Network variable value, if you want to switch to Holesky, Goerli.
global:
# Console output log level
LogLevel: info
# Debug logs file path
LogFilePath: ./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 space
LogFileBackups: 10
db:
# Path to a persistent directory to store the node's database.
Path: ./data/db
ssv:
# The SSV network to join to
# Mainnet = Network: mainnet (default)
# Testnet (Goerli) = Network: jato-v2
# Testnet (Holesky) = Network: holesky
Network: mainnet
ValidatorOptions:
# Whether to enable MEV block production. Requires the connected Beacon node to be MEV-enabled.
BuilderProposals: false
eth2:
# HTTP URL of the Beacon node to connect to.
BeaconNodeAddr: <ETH2_NODE> # e.g. <http://example.url:5052>
eth1:
# WebSocket URL of the Eth1 node to connect to.
ETH1Addr: <ETH1_WEBSOCKET_ADDRESS> # e.g. 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_JSON> # e.g. ./encrypted_private_key.json
PasswordFile: <PASSWORD_FILE> # e.g. ./password
# This enables monitoring at the specified port, see <https://docs.ssv.network/run-a-node/operator-node/maintenance/monitoring>
MetricsAPIPort: 15000
❗ Make sure your ETH1Addr
endpoint is communicating over WebSocket and not over HTTP to support subscriptions and notifications.
Start the Node
❗ Before starting the node, refer to this section, if you want to enable MEV.
Once you have completed the previous steps, you are ready to start your SSV node. This can be done in three ways:
Docker
docker-compose
Build from source
We will be moving on with Docker, if you want to try the other two options, you can refer here.
To start your node, run the following Docker command in the same folder you created the config.yaml
file in the previous step:
docker run --restart unless-stopped --name ssv_node -e \\
CONFIG_PATH=/config.yaml -p 13001:13001 -p 12001:12001/udp -p 15000:15000 \\
-v "$(pwd)/config.yaml":/config.yaml \\
-v "$(pwd)":/data \\
-v "$(pwd)/password":/password \\
-v "$(pwd)/encrypted_private_key.json":/encrypted_private_key.json \\
-it "bloxstaking/ssv-node:latest" make BUILD_PATH="/go/bin/ssvnode" start-node
❗ Do not run multiple instances of SSV Node with the same set of operator keys. This does not increase validator resiliency and could lead to validator slashing.
❗ This command will keep the terminal busy, showing the container's logs. It is useful to make sure that the node starts up the sequence and runs correctly.
You can detach the terminal at any time by hitting Ctrl-c
the key combination or closing the terminal itself. The node will be stopped but it will restart automatically, thanks to the --restart unless-stopped
startup parameter.
If you are sure that the node works, and don't care about the logs, you can add the -d
parameter right after docker run
.
Peer-to-peer ports configuration and firewall
When setting up your firewall, expose the default ports 12001 UDP and 13001 TCP, or adjust them in your config.yaml
and container creation command. Also, you can add your public static IP address (HostAddress) to the config.
p2p:
HostAddress: 206.22.63.189
UdpPort: 12001
TcpPort: 13001
Configuring MEV
Maximal extractable value (MEV) is the maximum value block producers (miners or validators) can obtain by including, reordering, or excluding transactions when producing a new block. This allows the validator to earn more rewards than usual.
In order to enable MEV in SSV you need to enable it in Beacon chain, for more reference you can refer here.
Once MEV is enabled in Beacon chain, Update the config.yaml
file in the SSV node to enable MEV for your operator:
ssv:
ValidatorOptions:
BuilderProposals: true
SSV-DKG
The ssv-dkg
tool enables operators to participate in ceremonies to generate distributed validator keys for Ethereum stakers.
It is separate from the ssv-node
and can be run on a different machine. However, the two are heavily correlated because the keyshare generated by the ssv-dkg
tool will ultimately be used by the Node itself to manage the related validator.
In more detail, the ssv-dkg
tool facilitates the creation of distributed validator keys through a process known as Distributed Key Generation (DKG). This process ensures that the validator keys are not controlled by a single entity, enhancing security and decentralization.
Once the distributed keys are generated, each operator involved in the DKG ceremony receives a keyshare. These keyshares are essential components that the ssv-node
uses to manage and validate transactions on the Ethereum network. The distributed nature of these keys means that no single operator can compromise the validator, adding an additional layer of security.
❗ If you want to join DKG ceremonies started by stakers and get more chances to run their validators, it's important to keep your ssv-dkg client online all the time
Additionally, to check logs, make sure you use permanent storage when running this software.
Prerequisites
In order to successfully participate in DKG ceremonies initiated by stakers, you will need to possess and/or provide the following information:
Operator ID: Your Operator ID is unique within the SSV network and helps in identifying your operator. You can obtain this when you register your operator on the SSV network.
Operator Key Pair:
Generating Keys (public key): You generate a key pair (public and private keys) during the initial setup of your operator. The public key will be shared with the network, while the private key should be kept secure and encrypted.
Encrypting Private Key (private key): If you have an unencrypted private key, you should follow the migration guide provided by SSV to encrypt it. This adds a layer of security, ensuring that even if the file is accessed, it cannot be used without a password.
Machine Endpoint: This is the address (IP or domain) and port number of the machine where you will run the ssv-dkg client. This endpoint is crucial as it allows the DKG client to participate in the key generation process and communicate with other nodes in the network.
You need this information because the DKG process involves multiple operators working together to generate distributed keys for Ethereum validators. Each operator's ID, keys, and endpoint ensure secure and coordinated participation in these ceremonies.
❗ You must use the same key as your SSV operator when running ssv-dkg
node. Using a different key will result in the inability to successfully complete the DKG ceremony.
Start SSV-DKG
❗ It is advised to launch the tool as a Docker image as it is the most convenient way and only requires to have Docker installed. The ssv.network team builds a Docker image with every release of the tool. If you want to try other options, you can find the link here.
All of the necessary configuration information can be provided in a YAML file.
Note:
A good way to manage all the necessary files (encrypted_private_key.json
, password
) is to store them in a single folder (in this case operator-config
), together with the operator.yaml
configuration file, like so:
Input:
tree operator-config
Output:
operator-config
├── encrypted_private_key.json
├── operator.yaml
└── password
1 directory, 3 files
With this configuration, a typical configuration file operator.yaml
would look like this:
privKey: /data/encrypted_private_key.json
privKeyPassword: /data/password
operatorID: <YOUR_OPERATOR_ID>
port: 3030
logLevel: info
logFormat: json
logLevelFormat: capitalColor
logFilePath: /data/debug.log
outputPath: /data/output
❗ In the config file above, /data/
represents the container's shared volume created by the docker
command itself with the -v
option.
Under the assumption that all the necessary files (encrypted_private_key.json
, operator.yaml
, password
) are under the same folder (represented below with <PATH_TO_FOLDER_WITH_CONFIG_FILES>
)
Now everything is setup, before spinning docker container, we need to setup SSL configuration.
SSL Configuration:
Launching the DKG tool as a Docker container allows the automatic creation and management of SSL certificates, but sometimes it doesn’t work well.
SSL configuration is crucial for securing communication between nodes and clients in a network. It ensures that data transmitted over the network is encrypted, preventing unauthorized access and maintaining data integrity. This is especially important in distributed systems like SSV nodes, where secure and reliable communication between operators and clients is essential to prevent attacks and data breaches.
Here is a small guide that I used:
Create tls.crt
and tls.key
using openssl.cnf
(you can create this file in /<PATH_TO_FOLDER_WITH_CONFIG_FILES>/ssl/openssl.cnf
), and then distribute it to your respective operator node servers. Although you can create multiple instances of tls.crt
and tls.key
, it's recommended to use a single file for all servers.
Here are the steps:
Input the IP address of all the servers in the
openssl.cnf
file.
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = GD
L = SZ
O = localhost, Inc.
CN = localhost
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 =
IP.2 =
IP.3 =
IP.4 =
Create
tls.crt
andtls.key
files using this command in the terminal.
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout "/ssl/tls.key" -out "/ssl/tls.crt" -config /ssl/openssl.cnf
The client must have the CA certificate used to sign the server certificates. If the certificates are self-signed, the client should have the certificates of all servers it will communicate with.
Create a Combined CA Certificate: If using self-signed certificates, combine all server certificates into a single CA certificate:
cat /<PATH_TO_FOLDER_WITH_CONFIG_FILES>/ssl/tls.crt > /<PATH_TO_FOLDER_WITH_CONFIG_FILES>/ssl/combined_ca_cert.pem
The server needs tls.crt and tls.key files. Copy them to the respective servers
Now you can run the tool using the command below:
docker run -u $(id -u):$(id -g) --restart unless-stopped --name ssv_dkg -p 3030:3030
-v "<PATH_TO_FOLDER_WITH_CONFIG_FILE>":/data -it "bloxstaking/ssv-dkg:latest"
start-operator --configPath /data/operator.yaml
--serverTLSCertPath "/ssl/tls.crt" --serverTLSKeyPath "/ssl/tls.key"
❗ A quick explanation of the command flags is due:
-u
flag makes sure the container will write any output as the current user--restart unless-stopped
makes sure that, in case of a crash, the container will automatically restart. It will only stop when manually stopped--name
provisions the container with a specific name, so it's easier to find, it withdocker ps
--serverTLSCertPath
provides a location for TLScert file--serverTLSKeyPath
provides location for TLSKey file </aside>
Just make sure to substitute <PATH_TO_FOLDER_WITH_CONFIG_FILES>
with the actual folder containing all the files (e.g. /home/my-user/operator-config/
).
You can change the configuration above to one that suits you better but must be mindful of changing the path references in the docker command and in the operator.yaml
file as well. The two need to be consistent with each other.
❗ This command will keep the terminal busy, showing the container's logs. It is useful to make sure that the tool start-up sequence runs correctly.
You can detach the terminal at any time by hitting Ctrl-c
key combination or closing the terminal itself. The tool will be stopped, but it will restart automatically, thanks to the --restart unless-stopped
startup parameter.
If you are sure that the tool works, and don't care about the logs, you can add the -d
parameter right after docker run
.
❗ When you set up your firewall on your DKG node machine, make sure to expose the port you set in the configuration (and the Docker container creation command, if running on Docker). The default is 3030.
Update Operator Metadata
❗ To participate in DKG ceremonies without coordination and to enable others to initiate ceremonies with you via your provided endpoint, it's crucial to update your operator metadata with the correct information.
Once the DKG tool is up and running, please make sure to update your operator metadata, and provide your DKG Operator endpoint, in the form of protocol:ip:port
(if you have a domain name, instead of an ip
that works as well).
Please head over to the Operator User guide on how to update metadata and follow the instructions
Test the setup
You can test out if your DKG node is correctly set, with these simple steps:
fetch operator metadata from SSV-API (e.g.
https://api.ssv.network/api/v4/<holesky | mainnet>/operators/<OPERATOR_ID>
choosing the right network and substituting your operator ID) and getdkg_address
from the outputrun the command:
docker run "bloxstaking/ssv-dkg:latest" ping --ip ${dkg_address}
wheredkg_address
comes from the previous step
It should tell you if the operator is online and is updated to the latest version.