Гайд по запуску Full Node и Validator в тестовой сети Monad
Важно перед началом
Этот пример установки показан на базе Hetzner Dedicated Server, потому что это удобный и понятный пример для демонстрации подготовки сервера.
Но мы не рекомендуем использовать Hetzner для запуска validator в Monad.
- Hetzner не считается crypto-friendly провайдером
- на Hetzner уже размещено много валидаторов
- высокая концентрация валидаторов у одного хостинг-провайдера ухудшает децентрализацию сети и создаёт дополнительные инфраструктурные риски для самого проекта
Если вы хотите запускать именно validator, лучше заранее проверить, где уже размещены другие операторы, и выбрать более уникальную комбинацию хостинга + локации.
Для этого мы сделали собственный dashboard валидаторов Monad, где можно посмотреть:
- в каких странах размещены валидаторы
- какие хостинг-провайдеры уже заняты
- какие локации и провайдеры перегружены
- где можно выбрать более уникальное размещение для лучшей децентрализации сети
Если вы запускаете full node, Hetzner ещё можно рассматривать как рабочий вариант для тестов. Но для validator лучше выбрать другого провайдера и более редкую географию.
Требования к серверу
⚠️ Облака (AWS, GCP, Azure и т.д.) официально не поддерживаются.
Минимальные требования
CPU
16 ядер с базовой частотой 4.5 GHz+
Примеры:
- RAM
Диски
- 2 TB NVMe (отдельный диск для TrieDB / Execution)
- 500 GB для OS и MonadBFT
- PCIe Gen4 x4 NVMe или лучше
Сеть
🔥 Лучшие NVMe (по тестам команды)
Компоненты ноды
Monad устанавливается как systemd-сервисы:
monad-bft— консенсусmonad-execution— execution clientmonad-rpc— RPC серверmonad-mpt— инициализация TrieDBmonad-cruft— очистка старых файловotelcol— метрики
Все сервисы работают от пользователя monad.
⚙️ Подготовка сервера
Требования к системе
⚠️ Версии kernel 6.8.0.56–59 вызывают зависания.
Подготовка сервера (пример Hetzner)
В этом разделе показано, как подготовить сервер для запуска ноды на примере Hetzner Dedicated Server.
Disk 1 → OS + MonadBFT Disk 2 → TrieDB / Execution
Это соответствует требованиям ноды:
Использовать RAID не рекомендуется, так как он может увеличивать latency и снижать IOPS для TrieDB.
Установка операционной системы
Servers → Rescue → Linux → Activate
ssh root@YOUR_SERVER_IP
installimage
Конфигурация дисков
При установке системы используйте только один диск для ОС.
DRIVE1 /dev/nvme0n1 #DRIVE2 /dev/nvme1n1 SWRAID 0 BOOTLOADER grub PART /boot ext3 1G PART swap swap 16G PART / ext4 500G PART /home ext4 all
Это создаст следующую структуру:
nvme0n1 ├─ /boot ├─ swap ├─ / └─ /home
Второй диск останется свободным и будет использоваться для TrieDB.
После установки перезагрузите сервер.
Проверка дисков
После установки системы выполните:
lsblk
nvme0n1 → OSnvme1n1 → пустой диск
Проверка версии Kernel
В Ubuntu 24.04 kernel устанавливается автоматически вместе с системой, поэтому обычно ничего дополнительно устанавливать не нужно.
Чтобы проверить текущую версию kernel, выполните:
uname -r
6.8.0-90-generic
Disable HyperThreading / SMT
Для корректной работы ноды рекомендуется отключить HyperThreading (Intel) / SMT (AMD), так как эти технологии могут снижать стабильность и производительность ноды.
Проверка состояния SMT
cat /sys/devices/system/cpu/smt/active
1
0
Дополнительно можно проверить:
lscpu | grep Thread
Thread(s) per core: 2
Thread(s) per core: 1
Отключение HyperThreading / SMT
Для стабильной работы ноды рекомендуется отключить HyperThreading (Intel) / SMT (AMD), так как эти технологии могут ухудшать производительность и стабильность ноды.
Стандартный способ (через GRUB)
nano /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX_DEFAULT="quiet nosmt"
Сохраните файл и примените изменения:
update-grub
reboot
Для серверов Hetzner
На некоторых серверах Hetzner параметры из файла /etc/default/grub могут быть переопределены конфигурацией Hetzner.
В этом случае необходимо изменить дополнительный конфигурационный файл.
nano /etc/default/grub.d/hetzner.cfg
GRUB_CMDLINE_LINUX_DEFAULT="consoleblank=0"
GRUB_CMDLINE_LINUX_DEFAULT="consoleblank=0 nosmt"
Применение изменений
После редактирования выполните:
update-grub
reboot
Проверка
cat /sys/devices/system/cpu/smt/active
0
lscpu | grep Thread
Thread(s) per core: 1
Обновление системы
apt update && apt upgrade -y
Если обновилось ядро — перезагрузить сервер.
Установка зависимостей
apt install -y curl nvme-cli aria2 jq
Установка Monad
cat <<EOF > /etc/apt/sources.list.d/category-labs.sources Types: deb URIs: https://pkg.category.xyz/ Suites: noble Components: main Signed-By: /etc/apt/keyrings/category-labs.gpg EOF
curl -fsSL https://pkg.category.xyz/keys/public-key.asc \ | gpg --dearmor --yes -o /etc/apt/keyrings/category-labs.gpg
Устанавливаем актуальную testnet-версию Monad:
apt update apt install -y monad=0.13.0 apt-mark hold monad
👤 Создание пользователя
useradd -m -s /bin/bash monad
mkdir -p /home/monad/monad-bft/config \
/home/monad/monad-bft/ledger \
/home/monad/monad-bft/config/forkpoint \
/home/monad/monad-bft/config/validators💾 Настройка TrieDB (ВАЖНО)
⚠️ Делайте это аккуратно. Нельзя форматировать системный диск.
nvme list lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL
Эти команды покажут все NVMe диски и их текущие точки монтирования.
NAME SIZE TYPE MOUNTP MODEL nvme1n1 3.5T disk SAMSUNG MZQL23T8HCLS-00A07 nvme0n1 3.5T disk SAMSUNG MZQL23T8HCLS-00A07 ├─nvme0n1p1 16G part [SWAP] ├─nvme0n1p2 1G part /boot ├─nvme0n1p3 500G part / ├─nvme0n1p4 3T part /home └─nvme0n1p5 1M part /home
nvme0n1 → системный диск nvme1n1 → свободный диск
Системный диск легко определить по точкам монтирования:
/ /boot swap /home
Такой диск использовать нельзя.
Выбор диска для TrieDB
Необходимо выбрать диск без разделов и без точек монтирования.
nvme1n1
Теперь указываем его в переменной:
TRIEDB_DRIVE=/dev/nvme1n1
Эта переменная будет использоваться в следующих командах для создания раздела TrieDB.
parted $TRIEDB_DRIVE mklabel gpt parted $TRIEDB_DRIVE mkpart triedb 0% 100%
PARTUUID=$(lsblk -o PARTUUID $TRIEDB_DRIVE | tail -n 1)
echo "Disk PartUUID: ${PARTUUID}"
echo "ENV{ID_PART_ENTRY_UUID}==\"$PARTUUID\", MODE=\"0666\", SYMLINK+=\"triedb\"" \
| tee /etc/udev/rules.d/99-triedb.rulesudevadm trigger udevadm control --reload udevadm settle ls -l /dev/triedb
Проверка LBA
nvme id-ns -H $TRIEDB_DRIVE | grep 'LBA Format' | grep 'in use'
Data Size: 512 bytes (in use)
nvme format --lbaf=0 $TRIEDB_DRIVE
Инициализация TrieDB
systemctl start monad-mpt && journalctl -u monad-mpt -n 14 -o cat
🔐 Настройка Firewall
ufw allow ssh ufw allow 8000 ufw allow 8001 ufw enable ufw status
sudo iptables -I INPUT -p udp --dport 8000 -m length --length 0:1400 -j DROP
📡 Установка OTEL (метрики)
OTEL_VERSION="0.139.0"
OTEL_PACKAGE="https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTEL_VERSION}/otelcol_${OTEL_VERSION}_linux_amd64.deb"
curl -fsSL "$OTEL_PACKAGE" -o /tmp/otelcol_linux_amd64.deb
dpkg -i /tmp/otelcol_linux_amd64.deb
cp /opt/monad/scripts/otel-config.yaml /etc/otelcol/config.yaml
systemctl restart otelcolhttp://IP:8889/metrics
📄 Получение конфигов
MF_BUCKET=https://bucket.monadinfra.com curl -o /home/monad/.env $MF_BUCKET/config/testnet/latest/.env.example curl -o /home/monad/monad-bft/config/node.toml $MF_BUCKET/config/testnet/latest/full-node-node.toml
MF_BUCKET=https://bucket.monadinfra.com curl -o /home/monad/.env $MF_BUCKET/config/testnet/latest/.env.example curl -o /home/monad/monad-bft/config/node.toml $MF_BUCKET/config/testnet/latest/node.toml
Генерация ключей (BLS и SECP)
Нода Monad использует два типа ключей:
• SECP key — используется для идентификации ноды
• BLS key — используется в консенсусе MonadBFT
Ключи сохраняются в зашифрованных keystore файлах.
Пароль для шифрования задаётся через переменную:
KEYSTORE_PASSWORD
/home/monad/.env
1. Генерация безопасного пароля
Если пароль ещё не задан в .env, можно сгенерировать случайный безопасный пароль:
sed -i "s|^KEYSTORE_PASSWORD=$|KEYSTORE_PASSWORD='$(openssl rand -base64 32)'|" /home/monad/.env source /home/monad/.env
cat /home/monad/.env
KEYSTORE_PASSWORD='random-generated-password'
2. Создание директории для бэкапов
Создаём директорию для резервных копий:
mkdir -p /opt/monad/backup
echo "Keystore password: ${KEYSTORE_PASSWORD}" > /opt/monad/backup/keystore-password-backup3. Генерация ключей
bash <<'EOF'
set -e
source /home/monad/.env
if [[ -z "$KEYSTORE_PASSWORD" || \
-f /home/monad/monad-bft/config/id-secp || \
-f /home/monad/monad-bft/config/id-bls ]]; then
echo "Skipping: missing KEYSTORE_PASSWORD or keys already exist."
exit 1
fi
monad-keystore create \
--key-type secp \
--keystore-path /home/monad/monad-bft/config/id-secp \
--password "${KEYSTORE_PASSWORD}" > /opt/monad/backup/secp-backup
monad-keystore create \
--key-type bls \
--keystore-path /home/monad/monad-bft/config/id-bls \
--password "${KEYSTORE_PASSWORD}" > /opt/monad/backup/bls-backup
grep "public key" /opt/monad/backup/secp-backup /opt/monad/backup/bls-backup \
| tee /home/monad/pubkey-secp-bls
echo "Success: New keystores generated"
EOF4. Где будут сохранены ключи
/home/monad/monad-bft/config/id-secp /home/monad/monad-bft/config/id-bls
/opt/monad/backup/secp-backup /opt/monad/backup/bls-backup
/home/monad/pubkey-secp-bls
5. Обязательный внешний backup
Необходимо обязательно сохранить эти файлы вне сервера:
/opt/monad/backup/secp-backup /opt/monad/backup/bls-backup /opt/monad/backup/keystore-password-backup
• на локальном компьютере
• в password manager
• в зашифрованном cloud storage
⚠️ Если сервер будет потерян и бэкапов не будет, восстановить validator identity будет невозможно.
Проверка
После генерации ключей можно проверить публичные ключи:
cat /home/monad/pubkey-secp-bls
Здесь будут отображены SECP и BLS public keys, которые могут понадобиться при регистрации валидатора.
🌐 Настройка node.toml
nano /home/monad/monad-bft/config/node.toml
Указываем beneficiary
beneficiary = "0x0000000000000000000000000000000000000000"
beneficiary = "0xВАШ_АДРЕС"
Указываем имя ноды
node_name = "full_blockpro_1"
✍️ Подпись Name Record
source /home/monad/.env
monad-sign-name-record \
--address $(curl -s4 ifconfig.me):8000 \
--authenticated-udp-port 8001 \
--keystore-path /home/monad/monad-bft/config/id-secp \
--password "${KEYSTORE_PASSWORD}" \
--self-record-seq-num 1Полученные данные вставляем в:
[peer_discovery] self_address self_record_seq_num self_name_record_sig
RaptorCast — как Full Node получает блоки
Full Node может получать блоки тремя способами.
1️⃣ Normal (стандартный публичный режим)
Это обычная конфигурация для большинства full node.
Нода автоматически подключается к валидаторам и получает приглашения в raptorcast-группы.
[fullnode_raptorcast] enable_client = true
[statesync] expand_to_group = true
Это режим по умолчанию и самый рекомендуемый.
2️⃣ Prioritized Secondary RaptorCast
В этом режиме валидатор вручную добавляет full node в список приоритетных.
- Требуется whitelist от валидатора
- Всё равно используется Secondary RaptorCast
- Нода получает гарантированные приглашения в группы
Используется, если вы договорились с валидатором о стабильном канале доставки блоков.
3️⃣ Dedicated (Chunk Forwarding)
Здесь валидатор напрямую форвардит full node все блоки из Primary RaptorCast.
В этом случае full node может работать с:
enable_client = false
Так как она не участвует во Secondary RaptorCast.
Что выбрать?
Если вы запускаете обычный публичный full node — выбирайте Normal режим.
Запуск сервисов
chown -R monad:monad /home/monad/ systemctl enable monad-bft monad-execution monad-rpc
Hard Reset (импорт снапшота)
bash /opt/monad/scripts/reset-workspace.sh
curl -sSL https://bucket.monadinfra.com/scripts/testnet/restore-from-snapshot.sh | bash
systemctl start monad-bft monad-execution monad-rpc
Что такое Statesync
monad-cruft
Сервис автоматически чистит старые:
Можно настроить время хранения в .env.
✅ Готово
Теперь ваша full node полностью запущена.
Если планируете стать валидатором — запускайте как full node заранее, чтобы не отставать от цепи.
Регистрация Validator в тестовой сети Monad
После того как нода полностью синхронизирована (statesync завершён, RPC активен, блоки идут), можно регистрировать валидатора.
Регистрация происходит вызовом функции addValidator в staking precompile.
Какие данные нужны для регистрации
Функция addValidator(bytes, bytes, bytes) принимает:
1️⃣ Payload (закодированные данные)
Внутри payload последовательно упакованы:
secpPubkey— публичный SECP ключ (для peer discovery и консенсуса)blsPubkey— публичный BLS ключ (для подписи блоков)authAddress— адрес управления валидатором (имеет право вывода средств)amount— self-stake (в MON)commission— комиссия * 1e18
Пример: 10% =1e17
Payload формируется аналогично abi.encodePacked() в Solidity.
2️⃣ signedSecpMessage
3️⃣ signedBlsMessage
⚠️ Важные правила
Регистрация отклонится (revert), если:
- любой из публичных ключей уже используется
- подписи невалидны
msg.value < MIN_AUTH_ADDRESS_STAKE- self-stake меньше минимума (100000 MON)
Условия для активации валидатора
После регистрации валидатор станет активным не сразу.
- Иметь stake ≥
ACTIVE_VALIDATOR_STAKE = 10 000 000 MON - Быть в топ-200 по stake
- Поддерживать self-stake ≥
MIN_VALIDATE_STAKE = 100 000 MON
Только при выполнении всех трёх условий он попадёт в активный сет.
Регистрация через Staking CLI (рекомендуемый способ)
Monad предоставляет официальный CLI инструмент.
Перед установкой CLI убедитесь, что на сервере установлен Python 3.8 или новее.
python3 --version
Python 3.12.3
Если Python не установлен, выполните установку:
apt update apt install python3 python3-venv python3-pip -y
Установка staking-sdk-cli
git clone https://github.com/monad-developers/staking-sdk-cli.git cd staking-sdk-cli python -m venv cli-venv source cli-venv/bin/activate # On Windows: cli-venv\Scripts\activate pip install .
Извлечение приватных ключей
⚠️ Нельзя использовать старые backup файлы напрямую.
source /home/monad/.env monad-keystore recover --password "$KEYSTORE_PASSWORD" --keystore-path /home/monad/monad-bft/config/id-secp --key-type secp monad-keystore recover --password "$KEYSTORE_PASSWORD" --keystore-path /home/monad/monad-bft/config/id-bls --key-type bls
Регистрация через CLI
python staking-cli/main.py add-validator \
--secp-privkey "${SECP_PRIVATE_KEY}" \
--bls-privkey "${BLS_PRIVATE_KEY}" \
--auth-address "${AUTH_ADDRESS}" \
--amount 100_000⚠️ Amount указывается в MON (не wei).
CLI сам конвертирует.
Проверка ключей
CLI покажет derived public keys:
SECP Pubkey: 03bbf6... BLS Pubkey: 985d3f...
Обязательно проверь совпадение с:
cat /home/monad/pubkey-secp-bls
Если подтвердить неправильные ключи — придётся делать key rotation.
✅ Успешная регистрация
Tx status: 1 Validator Created! ID: 19
Если статус 0 — транзакция провалилась.
Проверка, что валидатор добавлен
python main.py query validator-set --type execution --config-path ~/config.toml | grep {{ SECP PUBKEY }}Проверка конкретного валидатора:
python main.py query validator --validator-id 207
🔧 Общие операции и диагностика
Версия бинарников
Посмотреть версию и информацию о сборке:
monad-node --version
# Пример:
# monad-node {"commit":"c0cdcaae8eb527e44d72c4638c1f1335025a5132","tag":"v0.12.2-rc","branch":"","modified":true}CLI Help
Посмотреть доступные аргументы командной строки:
monad-rpc --help monad --help monad-bft --help
⚠️ Не меняйте CLI-аргументы наугад. Некоторые параметры могут привести к нестабильной работе или падениям.
Управление сервисами
Проверить статус всех сервисов сразу:
systemctl status monad-bft monad-execution monad-rpc --no-pager -l
systemctl status monad-bft systemctl status monad-execution systemctl status monad-rpc
Смотреть логи в реальном времени:
journalctl -u monad-bft -f journalctl -u monad-execution -f journalctl -u monad-rpc -f
Мониторинг высоты блоков
RPC начнёт слушать порт восемь ноль восемь ноль после завершения statesync.
Проверить текущую высоту блока через RPC:
curl http://localhost:8080/ \
-X POST \
-H "Content-Type: application/json" \
--data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}'Использование диска MonadDB (TrieDB)
TrieDB автоматически делает компакцию примерно при восьмидесяти процентах заполнения, чтобы сохранять производительность SSD.
Проверить использование TrieDB и глубину истории:
monad-mpt --storage /dev/triedb
MPT database on storages:
Capacity Used % Path
3.49 Tb 24.30 Gb 0.68% "/dev/nvme1n1p1"
MPT database internal lists:
Fast: 94 chunks with capacity 23.50 Gb used 23.40 Gb
Slow: 3 chunks with capacity 768.00 Mb used 658.72 Mb
Free: 14207 chunks with capacity 3.47 Tb used 0.00 bytes
MPT database has 599928 history, earliest is 36784905 latest is 37384832.
It has been configured to retain no more than 33554432.
Latest proposed is (37384832, 88a5550ba067c2f21cef6b6e8953fbf700fe300905952e5621335fe2bd58729c).
Latest voted is (37384831, 56074c2429909c2966bfe8df55810ec3b8f4f4f599b407ff89ec92b090656ab1).
Latest finalized is 37384830, latest verified is 37384827, auto expire version is 36784905Анализ логов через monlog
monlog — лёгкая утилита от Category Labs: парсит BFT-логи и выдаёт статус и подсказки. Анализирует примерно последние шестьдесят секунд логов.
Установка
Сначала (от root) даём пользователю monad доступ к systemd journal:
usermod -a -G systemd-journal monad
Если вы уже залогинены под monad, нужно перелогиниться, либо:
su - monad
Дальше (под пользователем monad) скачиваем monlog:
cd /home/monad curl -sSL https://pub-b0d0d7272c994851b4c8af22a766f571.r2.dev/scripts/monlog -O chmod u+x ./monlog
sha256sum ./monlog # Ожидаемый пример:# f8a1066d8c093bbdb5f722f5b3d89904c17a76fa01fa1dd62e950f445e88327f ./monlog
Запуск
./monlog
watch -d "./monlog"
Последние десять строк собранных логов:
./monlog -r
Показать secp ключи с маппингом на имена валидаторов:
./monlog -n
./monlog --no-color
Информация о консенсусе через ledger-tail
monad-ledger-tail читает консенсусные артефакты ledger и стримит JSON.
systemctl start monad-ledger-tail
journalctl -fu monad-ledger-tail
Статус ноды через monad-status
curl -sSL https://bucket.monadinfra.com/scripts/monad-status.sh -o /usr/local/bin/monad-status chmod +x /usr/local/bin/monad-status
monad-status
Вывод будет примерно в таком формате:
### Monad Node Status
hostname: monad-node
date: Wed Nov 26 10:48:26 PM CET 2025
uptime: 0d 00h 41m 49s
version: 0.12.2
config:
network: mainnet
chain: monad_mainnet
chainId: 143
secpPublicKey: 03831b36b50261011d82f94d58f8aa0edfe058359e2c365c37cce678436b9eb371
blsPublicKey: b9c1905e11e8395a789bece454ec24bed98b96cf9dc04c02c9512fb94900d3e0355383e542c44a0eb1be4d2780a1fb2f
nodeSignature: 4f6e3e47af0e8ff3614e1eb53f9015ef4fc8593e60c13d52c2b458d05385b5f94cff8776ceb8b9401c3647148637d599622353d0631864a23b07f6d7fb55e84f00
selfAddress: 65.109.145.172:8000
recordSeqNum: 0
services:
monad-bft: running
monad-execution: running
monad-rpc: running
otelcol: running
monad-cruft:
activated: true
previous: 48min ago
next: 11min
peers:
peersNumber: 1146
consensus:
status: in-sync
mode: live
epoch: 764
round: 38259075
blockNumber: 38200041
blockNumberFromExternal: 38200040
blockDifference: 0
statesync:
percentage: 100.0000%
progress: 38193694
target: 38193694
rpc:
status: active
clientVersion: Monad/0.12.2
netVersion: 143
blockNumber: 38200041