Skip to content

Плагин Webserver ​

Плагин webserver предоставляет HTTP и WebSocket конечные точки, перенаправляющие JSON-RPC запросы в плагин json_rpc. Включает кеш ответов, ключом которого служит method + params (не id), инвалидируемый при каждом применённом блоке, и пул потоков для параллельной обработки запросов.

Исходник: plugins/webserver/webserver_plugin.cpp


Зависимости ​

json_rpc::plugin

Конфигурация ​

ОпцияПо умолчаниюОписание
webserver-http-endpoint—Адрес прослушивания HTTP, например 0.0.0.0:8090
webserver-ws-endpoint—Адрес прослушивания WebSocket, например 0.0.0.0:8091
webserver-thread-pool-size256Рабочие потоки для обработки HTTP и WebSocket запросов.
webserver-cache-enabledtrueВключить кеш ответов.
webserver-cache-size10000Максимальное количество кешированных ответов. Кеш полностью вытесняется при достижении этого лимита.
webserver-stats-enabledfalseВключить учёт запросов по IP, лог статистики и (если не переопределено) лимиты.
webserver-limits-enabledзначение webserver-stats-enabledПрименять лимиты по IP. Лимитам нужны счётчики из webserver-stats-enabled.
webserver-limit-m1000Максимум запросов с одного IP в минуту.
webserver-limit-h10000Максимум запросов с одного IP в час.
webserver-limit-d100000Максимум запросов с одного IP в сутки.
webserver-stats-log<data-dir>/webserver-stats.logПуть лога статистики; ротация по размеру.
webserver-stats-log-max-size10485760 (10 MiB)Ротировать лог при превышении размера.
webserver-stats-log-keep5Сколько ротированных файлов (.1 … .N) хранить.
webserver-stats-interval60Интервал в секундах между снимками в лог статистики.
webserver-admin-state<data-dir>/webserver-admin.jsonЖивое состояние (лимиты, списки IP, флаг статистики), сохраняемое node_admin.

Для работы плагина должно быть задано хотя бы одно из webserver-http-endpoint или webserver-ws-endpoint. Оба могут быть включены одновременно.

Опции статистики и лимитов — только стартовое значение. После запуска живые значения принадлежат плагину и меняются через node_admin (см. Управление статистикой и лимитами на ходу); каждое изменение применяется к следующему запросу и сохраняется в webserver-admin-state.


Минимальный config.ini ​

ini
plugin = webserver

webserver-http-endpoint = 0.0.0.0:8090
webserver-ws-endpoint   = 0.0.0.0:8091

Кеш ответов ​

Что кешируется ​

Каждый ответ JSON-RPC только для чтения подходит для кеширования. Ключ кеша — это SHA-256 хеш method + params — намеренно исключая id, чтобы ротация id запроса не могла обойти кеш.

Что никогда не кешируется ​

Пространство имёнПричина
network_broadcast_api.*Изменяющий состояние (трансляция транзакций/блоков)
Некорректные/нераспознаваемые запросыНевозможно надёжно вычислить ключ

Пакетные запросы (JSON-массив) обрабатываются как единственная атомарная запись кеша с ключом на основе хеша полного массива.

Инвалидация ​

Кеш очищается при каждом применённом блоке. Ответы никогда не обслуживаются устаревшими дольше одного интервала блока (3 секунды до HF16, 1 секунда после).

Отключение кеша ​

ini
webserver-cache-enabled = false

Отключите для узлов, обслуживающих клиентов с высокими требованиями к задержке или клиентов реального времени, для которых окно кеша (3 секунды до HF16, 1 секунда после) неприемлемо.


Пул потоков ​

Серверы HTTP и WebSocket каждый работают на выделенном экземпляре io_service. Входящие запросы направляются в общий пул потоков из webserver-thread-pool-size рабочих.

Рекомендации по размеру:

  • Публичный API-узел со смешанным трафиком чтения/записи: 256 (по умолч.) достаточно для большинства нагрузок.
  • Высокопроизводительные узлы: увеличьте до 512 или более. Следите за насыщением CPU — больше потоков, чем ядер CPU, не помогает для операций, ограниченных CPU.
  • Разработка/локальный узел: достаточно 4–8.

Учёт запросов и лимиты ​

По умолчанию выключено. webserver-stats-enabled = true включает подсчёт запросов по IP-адресу клиента и лимиты (или задайте webserver-limits-enabled явно, чтобы разделить эти две вещи).

Лимиты ​

ОкноПо умолчанию
минута1000 запросов
час10000 запросов
сутки100000 запросов

Окна фиксированные (минутная корзина сбрасывается на границе минуты, часовая — на границе часа, суточная — в полночь UTC), и каждый запрос проверяется по всем трём. Запрос сверх любого лимита отклоняется:

  • HTTP: 429 Too Many Requests, Retry-After: 60, тело rate limit exceeded.
  • WebSocket: ошибка JSON-RPC -32006 rate limit exceeded.

Это осознанная защита от скрапинга и парсерного трафика: тем, кому нужно больше, следует поднимать свою ноду.

Списки ​

  • Белый список — адреса, обходящие лимиты. Они всё равно считаются и видны в статистике.
  • Чёрный список — адреса, получающие 403 Forbidden (HTTP) или -32005 forbidden (WebSocket). Чёрный список важнее белого. Он действует даже при выключенной статистике.
  • Добавление адреса в один список удаляет его из другого.

Что содержит лог статистики ​

Каждые webserver-stats-interval секунд плагин дописывает строку на каждый отслеживаемый IP плюс итог:

text
2026-10-19T12:00:00Z ip=203.0.113.7 total=4210 minute=320 hour=4210 day=4210 blocked=0 limited=3 whitelisted=0 blacklisted=0 last_seen=1760875200
2026-10-19T12:00:00Z summary total_requests=4210 blocked_requests=0 limited_requests=3 tracked_ips=1

Файл ротируется по размеру: <имя> становится <имя>.1, старые файлы сдвигаются в .2 … .webserver-stats-log-keep, самый старый удаляется.

Адрес клиента ​

Плагин использует TCP-адрес пира соединения. За nginx все запросы выглядят приходящими от прокси (127.0.0.1), поэтому лимиты по IP становятся глобальными, а отчёт показывает одну строку. Варианты: публиковать API напрямую, внести прокси в белый список и ограничивать на уровне прокси (limit_req), либо включить поддержку PROXY protocol на уровне прокси/сети.

Управление статистикой и лимитами на ходу ​

Изменяющие методы требуют скоупа webserver у токена node_admin; чтению достаточно read:

МетодНазначение
admin.webserver.statusЛимиты, итоги, списки IP, число отслеживаемых адресов
admin.webserver.ipsСчётчики по IP (limit до 5000), сортировка по числу запросов
admin.webserver.limitsИзменить enabled, per_minute, per_hour, per_day (опущенные поля сохраняют значение)
admin.webserver.statsВключить/выключить учёт (`{"enabled": true
admin.webserver.whitelist_add / whitelist_removeПравка белого списка ({"ip": "..."})
admin.webserver.blacklist_add / blacklist_removeПравка чёрного списка ({"ip": "..."})
admin.webserver.resetОбнулить счётчики, сохранив списки и лимиты
admin.webserver.reloadПеречитать webserver-admin-state с диска

Каждый из них также доступен как MCP-инструмент с тем же именем. Изменения применяются к живому плагину сразу — без перезапуска и без перечитывания config.ini. Они записываются в webserver-admin-state (атомарно: временный файл + rename), который восстанавливает политику при совпадении отпечатка config_policy со стартовыми stats/limits. Изменённые параметры config.ini имеют приоритет; IP-списки восстанавливаются независимо. Старые файлы без отпечатка восстанавливают только IP-списки. Сам config.ini не перезаписывается. reload нужен оператору, правившему JSON руками; обычным изменениям он не требуется.

json
{"jsonrpc":"2.0","id":1,"method":"admin.webserver.limits",
 "params":{"per_minute":600,"per_hour":8000}}

WebSocket-подписки ​

WebSocket-клиенты могут регистрировать колбеки:

МетодОписание
database_api.set_block_applied_callbackВызывается при каждом применённом блоке с заголовком блока
database_api.set_pending_transaction_callbackВызывается, когда транзакция поступает в пул ожидания
database_api.cancel_all_subscriptionsОтписаться от всех колбеков

Подписки требуют постоянного WebSocket-соединения. Они недоступны по обычному HTTP.


CORS ​

Плагин webserver обрабатывает межсайтовые (cross-origin) запросы браузера самостоятельно — для локальных и dev-окружений обратный прокси не требуется.

Preflight-запросы (OPTIONS) получают немедленный ответ с заголовками:

Заголовок ответаЗначение
Access-Control-Allow-Origin*
Access-Control-Allow-MethodsPOST, GET, OPTIONS
Access-Control-Allow-HeadersContent-Type, Authorization
Access-Control-Max-Age86400

Все остальные HTTP-ответы содержат Access-Control-Allow-Origin: *.

Это позволяет браузерным кошелькам и dApp обращаться к JSON-RPC-эндпоинту напрямую. Нода сама разрешает CORS — она проставляет эти заголовки в каждом ответе, в том числе работая за обратным прокси. Поэтому конфиг nginx из раздела «Публикация API через HTTPS (nginx + certbot)» ниже только проксирует запросы и не ставит собственных CORS-заголовков.

Не добавляйте add_header Access-Control-Allow-Origin на уровне nginx, если его уже ставит нода: два одинаковых заголовка заставят браузер отклонить ответ. Если вы дополнительно отдаёте статику (API-эксплорер или SPA) с того же домена, добавляйте CORS-заголовок только на статичных локациях — и только для GET/HEAD — чтобы у проксируемых ответов оставался единственный заголовок, проставленный нодой.


Безопасность ​

  • Привяжите к localhost (127.0.0.1) и используйте обратный прокси (nginx/Caddy) для публичного доступа. Привязка к 0.0.0.0 открывает RPC напрямую в сеть.
  • Плагин не имеет встроенной аутентификации. Есть необязательные лимиты по IP и списки адресов (см. Учёт запросов и лимиты), но это грубые инструменты — аутентификацию и общую фильтрацию держите на уровне обратного прокси.
  • Мутирующие методы (network_broadcast_api) защищены от отравления кеша по замыслу, но они остаются доступными для вызова с любого подключённого клиента — при необходимости ограничьте доступ на сетевом уровне.

Устранение неполадок ​

СимптомПроверка
Порт уже занят при запускеДругой процесс привязан к настроенному порту; измените порт или завершите конфликтующий процесс
Высокое использование памятиУменьшите webserver-cache-size или отключите кеширование
Медленные ответы под нагрузкойУвеличьте webserver-thread-pool-size; проверьте насыщение CPU
WebSocket-подписки не срабатываютПодписки требуют WebSocket-соединения, а не HTTP
Устаревшие ответыЕсли webserver-cache-enabled = true, ответы актуальны в пределах одного интервала блока (~3 с до HF16, ~1 с после); для использования в реальном времени отключите кеш

Публикация API через HTTPS (nginx + certbot) ​

Привяжите узел к localhost, затем поставьте перед ним nginx. certbot автоматически дополнит конфиг при запуске certbot --nginx.

1. config.ini узла ​

ini
webserver-http-endpoint = 127.0.0.1:8090
webserver-ws-endpoint   = 127.0.0.1:8091

2. /etc/nginx/sites-enabled/viz-node ​

nginx
server {
    listen 80;
    server_name your.domain.com;  # ← замените на ваш домен

    # ACME-challenge для certbot
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        proxy_pass http://127.0.0.1:8090;
        proxy_http_version 1.1;

        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 60s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;
    }
}

3. Получить TLS-сертификат ​

bash
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d your.domain.com

certbot автоматически добавит блок listen 443 ssl, директивы ssl_certificate и редирект HTTP→HTTPS. После этого узел доступен по адресу https://your.domain.com.

WebSocket через HTTPS ​

WebSocket-клиентам нужна проксировка заголовка Upgrade. Добавьте отдельный location (или второй server block на порту 8091):

nginx
location /ws {
    proxy_pass http://127.0.0.1:8091;
    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host       $host;
    proxy_read_timeout 3600s;
}

См. также: Обзор плагинов, Database API, JSON-RPC API.

Доверенные reverse proxy и сохранение политики ​

По умолчанию адрес берётся из TCP-соединения. За nginx явно задайте webserver-trusted-proxy = 127.0.0.1 (повторите для каждого IP своего прокси) и передавайте X-Forwarded-For. Цепочка разбирается справа налево до первого недоверенного узла; произвольные клиентские IP в доверенные не добавляйте.

При достижении 200000 IP удаляются записи старше суток; пока места нет, новые источники отклоняются, а действующие окна лимитов не сбрасываются. Включённые лимиты работают и без статистического логирования. Лог записывает изменённые строки, форматирование и дисковая запись вынесены из mutex приёма запросов. Отпечаток config_policy позволяет новым параметрам config.ini перекрыть старую runtime-политику, сохранив IP-списки.