Основы
Конфигурация — это TOML файл, по
умолчанию с именем nostrfy.toml. Создайте его командой init:
nostrfy --config nostrfy.toml init
Проверьте его (рекомендуется перед каждым запуском):
nostrfy --config nostrfy.toml check
Каждая команда принимает --config <path> (по умолчанию nostrfy.toml).
Общий синтаксис:
[section]
key = "string"
key = 8080
key = [1, 2]
key = true
Разделы конфигурации
| Раздел | Назначение |
|---|
[relay] | Идентичность, URL и переключатели NIP |
[server] | Сетевая привязка, разделение API, метрики |
[rpc] | NIP-86 управляющий RPC (аутентификация, лимит тела) |
[limits] | Все лимиты и защита от перегрузки |
[database] | Хранилище LMDB, поисковый индекс, лимиты очередей |
[daemon] | PID-, лог- и stats-файлы и ротация |
[access] | Начальные списки контроля доступа (изменяемые в процессе работы) |
[blossom] | Файловый сервер Blossom (хостинг медиа) |
Каждый ключ необязателен; отсутствующий ключ использует значение по умолчанию.
Раздел [relay] — идентичность релея
| Ключ | Тип | По умолчанию | Описание |
|---|
name | string | "nostrfy" | Имя релея, показываемое клиентам через NIP-11 |
description | string | "A minimal and stable Nostr relay" | Описание релея (NIP-11) |
pubkey | string (64 hex) | "" | Публичный ключ администратора (поле pubkey в NIP-11) |
contact | string | "" | Контактный URI администратора (mailto: или https://) |
icon | string | "" | URL изображения-иконки релея |
post_policy | string | "" | URL на политику публикации релея |
private_key | string (64 hex) | "" | Собственный секретный ключ релея; нужен для групп NIP-29 |
public_url | string | "" | Публичный URL, напр. wss://relay.example.com |
livekit_url | string | "" | URL сервера LiveKit для аудио/видео комнат NIP-29 |
livekit_api_key | string | "" | API-ключ LiveKit |
livekit_api_secret | string | "" | API-секрет LiveKit (для подписи JWT) |
enabled_nips | array of integers | [] | Явный список разрешённых NIP |
disabled_nips | array of integers | [] | NIP для отключения (игнорируется, если enabled_nips не пуст) |
reject_ephemeral | boolean | false | Отклонять эфемерные события NIP-01 (kinds 20000-29999) |
enabled_git | boolean | false | Принимать git-события NIP-34 (kinds 1617-1633, 30617/30618) |
require_pow | integer | 0 | Требуемое доказательство работы в ведущих нулевых битах |
new_pubkey_min_age_secs | integer | 0 | Отклонять события от ключей моложе этого (секунды; 0 = выкл.) |
max_events_per_min_per_pubkey | integer | 0 | Лимит публикации на ключ (в минуту; 0 = без лимита) |
max_groups | integer | 1000 | Лимит in-memory хранилища групп NIP-29 |
require_auth | boolean | false | Требовать аутентификацию NIP-42 для REQ/EVENT/COUNT/NEG |
send_auth_challenge | boolean | true | Отправлять AUTH-challenge при подключении |
enabled_nip78_auth | boolean | true | Требовать NIP-42 AUTH перед приёмом событий kind 78/30078 |
enabled_command_events | boolean | false | Выполнять операторские команды kind:1 от admin-ключа |
Детали ключей
- private_key — собственный секретный ключ релея, которым подписываются сгенерированные релеем события: метаданные
групп NIP-29 (39000-39005) и события ролей/участников NIP-43. Создайте командой
nostrfy genkey; храните в
секрете. Читается один раз при запуске, поэтому его изменение требует перезапуска. - public_url — используется для проверки тегов с URL от клиентов: NIP-42 AUTH, NIP-62 vanish и
NIP-98 admin auth. Если пусто, релей откатывается к
host:port, который никогда не совпадёт с реальным
URL клиента при привязке 0.0.0.0 или 127.0.0.1 (пишется предупреждение). Всегда задавайте его. - enabled_nips против disabled_nips — побеждает список разрешённых: когда
enabled_nips не пуст, рекламируются только его NIP, а disabled_nips игнорируется. Оба требуют перезапуска. - reject_ephemeral — kinds 20000-29999 отклоняются, но освобождённые kinds, которые NIP требуют
ретранслировать, всё равно пересылаются: 22242, 27235, 28934/28935/28936, 24133, 23194/23195, 24242 и 21059. Применяется по
SIGHUP.
- enabled_git — опциональный NIP-34: принимает kinds 1617-1633 и 30617/30618 и рекламирует NIP-34.
По умолчанию выключен, т.к. патчи могут быть большими. Применяется по SIGHUP.
Раздел [server] — настройки сервера
| Ключ | Тип | По умолчанию | Описание |
|---|
host | string | "127.0.0.1" | Адрес привязки; 0.0.0.0 принимает соединения отовсюду |
port | integer | 8080 | Порт (1-65535); порт 80 требует root |
api_host | string | "" | Имя хоста, выделенное под REST API |
metrics_enabled | boolean | true | Отдавать метрики Prometheus на /metrics |
ws_paths | string | "root" | Пути конечных точек WebSocket: root, inbox-outbox или all |
inbox_write_policy | string | "any" | Кто может писать в /inbox: «any» или «relay» (события всё равно должны нести p-тег) |
outbox_write_policy | string | "any" | Кто может писать в /outbox: «any» (собственные события NIP-42-аутентифицированного ключа) или «relay» |
trusted_proxies | array of strings | [] | Адреса/CIDR обратных прокси, чьему X-Forwarded-For доверяем (пусто = не доверять никому) |
Детали ключей
- host —
0.0.0.0 привязывает все интерфейсы IPv4; 127.0.0.1 — только локально. - port — 1-65535; порт 80 требует root. Этот один порт обслуживает WebSocket-релей, NIP-11 документ, REST API и NIP-86 RPC вместе.
- api_host — выделяет REST API под одно имя хоста, чтобы API и релей могли делить один
порт за обратным прокси. Фиксируется при запуске — требует перезапуска.
- ws_paths —
root обслуживает только /, inbox-outbox обслуживает только /inbox и
/outbox, all — и то, и другое. Фиксируется при запуске — требует перезапуска. - trusted_proxies — перечисляйте только собственные адреса прокси (loopback для nginx/Caddy на том же
хосте, диапазон источника балансировщика в облаке). Если задано, IP клиента выводится из последней недоверенной
записи
X-Forwarded-For для лимитов на IP, ограничения скорости, blockip и журналов. Никогда
не добавляйте адрес, доступный клиентам напрямую — они смогут подделать заголовок и обойти per-IP лимиты.
Фиксируется при запуске — требует перезапуска.
Раздел [rpc] — управление NIP-86
| Ключ | Тип | По умолчанию | Описание |
|---|
management_token | string | "" | Bearer-токен для управляющих API |
admin_pubkey | string (64 hex) | "" | Публичный ключ администратора для NIP-98 auth управления |
max_admin_body_bytes | integer | 65536 | Лимит тела для управляющего RPC NIP-86 |
NIP-86 RPC смонтирован на публичных маршрутах релея POST / — отдельного управляющего
порта нет. management_token и admin_pubkey иногда встречаются под [server] в старых гайдах; эти написания — устаревшие алиасы этих ключей [rpc].
Раздел [limits] — лимиты и защита
Соединения и сообщения
| Ключ | Тип | По умолчанию | Описание |
|---|
max_connections | integer | 10000 | Максимум одновременных соединений |
max_connections_per_ip | integer | 64 | Максимум соединений на исходный IP |
max_ws_message_bytes | integer | 1048576 | Максимум байт на WebSocket-сообщение/фрейм |
socket_recv_buffer_kb | integer | 64 | Ядерный приёмный буфер на соединение (KiB) |
max_out_queue_bytes | integer | 262144 | Лимит исходящей очереди на соединение (байты) |
ws_idle_timeout_secs | integer | 300 | Закрывать простаивающие соединения через это время |
http_read_timeout_secs | integer | 30 | Таймаут заголовка HTTP-запроса (защита от slow-loris) |
max_connections_per_sec_per_ip | integer | 0 | Максимум новых соединений в секунду на исходный IP |
Подписки и запросы
| Ключ | Тип | По умолчанию | Описание |
|---|
max_filters | integer | 20 | Максимум фильтров на REQ |
max_subscriptions | integer | 20 | Максимум подписок на соединение |
max_limit | integer | 500 | Потолок для REQ limit |
max_count | integer | 2000 | Потолок для результатов COUNT |
max_sub_id_len | integer | 64 | Макс. длина id подписки (символы, не байты) |
max_sub_bytes | integer | 1048576 | Суммарный размер фильтров подписок на соединение |
max_req_response_bytes | integer | 33554432 (32 MB) | Потолок суммарных байт, которые может отправить один ответ REQ |
События
| Ключ | Тип | По умолчанию | Описание |
|---|
max_content_bytes | integer | 65536 | Макс. длина content события в символах |
max_tags | integer | 2000 | Максимум тегов на событие |
max_tag_value_bytes | integer | 1024 | Максимум байт на значение тега |
max_created_at_future_secs | integer | 3600 | Допустимый уход created_at в будущее |
group_late_publish_secs | integer | 3600 | Допустимое отставание админ-событий групп NIP-29 (секунды) |
max_neg_items | integer | 100000 | Максимум записей на NIP-77 negentropy-синхронизацию |
Устаревшие алиасы: limits.require_pow, limits.new_pubkey_min_age_secs и limits.max_indexed_words по-прежнему принимаются как алиасы relay.require_pow, relay.new_pubkey_min_age_secs и database.max_indexed_words.
REST API
| Ключ | Тип | По умолчанию | Описание |
|---|
max_api_concurrent | integer | 8 | Максимум одновременных запросов /api/v1 |
max_api_limit | integer | 5000 | Потолок параметра limit API |
max_api_offset | integer | 50000 | Потолок параметра offset API |
max_api_fetch | integer | 55001 | Макс. окно предвыборки для offset-запросов — должно покрывать max_api_offset + max_api_limit + 1 (0 = без ограничения) |
max_api_search_bytes | integer | 2048 | Максимум байт параметра search API |
Живая рассылка
| Ключ | Тип | По умолчанию | Описание |
|---|
live_batch_interval_ms | integer | 20 | Как часто сбрасываются живые события (мс) |
live_batch_size | integer | 32 | Максимум событий на живой батч |
live_buffer | integer | 65536 | Размер очереди живой рассылки |
Раздел [database] — база данных
| Ключ | Тип | По умолчанию | Описание |
|---|
path | string | "./data" | Каталог базы данных (LMDB) |
max_dbs | integer | 32 | Максимум именованных баз LMDB |
max_readers | integer | 128 | Максимум одновременных читателей LMDB |
map_size | integer | 1073741824 (1 GB) | Нижняя граница размера memory map (байты) |
max_map_size | integer | 1099511627776 (1 TB) | Потолок memory-map (байты) |
purge_interval_secs | integer | 300 | Интервал очистки NIP-40 (секунды) |
search_index | boolean | true | Включить словесный индекс NIP-50 |
reader_threads | integer | 2 | Выделенные потоки сканирования |
max_indexed_words | integer | 32 | Слов content каждого события индексируется для поиска |
meta_index | boolean | true | Писать заголовок метаданных события для предфильтра сканирования |
disabled_fsync | boolean | false | Пропускать синхронный сброс на диск после каждого батча записи |
db_buffer_size | integer | 2048 | Начальный WebSocket-буфер на соединение (байты) |
db_request_timeout_secs | integer | 30 | Сколько запрос к базе может ждать перед ошибкой |
max_db_queue_msgs | integer | 4096 | Максимум сообщений в очереди перед быстрым отказом |
max_db_queue_events | integer | 262144 | Максимум событий в батчах очереди перед быстрым отказом |
max_db_queue_bytes | integer | 268435456 (256 MiB) | Максимум байт запросов к базе в очереди перед быстрым отказом (0 = без байтового лимита) |
Детали ключей
- map_size — нижняя граница memory map: карта всегда открывается не меньше этого размера.
- max_map_size — потолок, открывается как разреженное виртуальное резервирование: физический диск растёт только
с реально записанными данными. Повысьте его при
database map is full. - search_index = false — поиск всё равно работает (полнословное сопоставление с content), но сканирования
становятся медленнее; на крошечном VPS это вдвое уменьшает базу. Рекомендуется на маленьких инстансах.
- disabled_fsync — компромисс надёжности ради пропускной способности: записи фиксируются в page cache ОС, и
потеря питания может уничтожить самые свежие записи.
Раздел [daemon] — демон
| Ключ | Тип | По умолчанию | Описание |
|---|
pid_file | string | "./nostrfy.pid" | Путь к PID-файлу |
log_file | string | "./nostrfy.log" | Путь к лог-файлу |
stats_file | string | "./nostrfy.stats.json" | Путь к файлу статистики |
stats_interval_secs | integer | 5 | Интервал записи статистики (секунды) |
max_log_size_bytes | integer | 52428800 (50 MB) | Размер ротации лога (0 = без ротации) |
max_log_files | integer | 5 | Сколько поколений ротированных логов хранить |
Пути разрешаются относительно каталога файла конфигурации, поэтому остаются корректными после смены рабочего каталога демоном.
Раздел [access] — контроль доступа
| Ключ | Тип | По умолчанию | Описание |
|---|
restrict_relay | boolean | false | Публиковать могут только ключи из списка разрешённых |
blocked_kinds | array of integers | [] | Kinds для отклонения |
allowed_kinds | array of integers | [] | Список разрешённых kinds; если не пуст, принимаются только эти kinds |
blocked_ips | array of strings | [] | IP-адреса, отклоняемые при подключении |
method_grants | table: pubkey → array of strings | {} | Гранты методов NIP-86 для не-админ ключей (управляются в процессе работы через assignmethod) |
Списки разрешённых/запрещённых ключей — не ключи конфигурации — они хранятся в базе релея (LMDB) и
управляются в процессе работы:
nostrfy relay allow npub1...
nostrfy relay deny npub1...
nostrfy relay list
- restrict_relay = true — только ключи из списка разрешённых могут публиковать, а
чтение остаётся открытым для всех (любой клиент может подписываться и читать).
- Запрещённый ключ всегда отклоняется при публикации и никогда не обслуживается при чтении.
- method_grants — гранты методов NIP-86 для не-админ ключей (ключ → имена методов, напр. модератору
разрешены
banevent и listbannedevents). При первом запуске засеиваются из конфигурации,
затем управляются в процессе работы через NIP-86 assignmethod/unassignmethod (просмотр через listmethodassignees). Выдавать можно только модерационные и читающие методы —
управление правами, ролями, инвайтами и идентичностью релея остаётся только админским, а забаненный ключ
отклоняется даже с грантами. См. управляющий API.
Раздел [blossom] — файловый сервер Blossom
| Ключ | Тип | По умолчанию | Описание |
|---|
host | string | "" | Имя хоста сервера Blossom (пусто = отключено) |
storage | string | "local" | Бэкенд: «local» (local_path) или «s3» (S3-совместимый бакет) |
local_path | string | "/var/lib/nostrfy/images" | Локальный корень хранилища медиафайлов |
max_upload_bytes | integer | 20971520 (20 MB) | Макс. размер медиафайла |
min_free_bytes | integer | 33554432 (32 MB) | Свободного места ниже — загрузки отклоняются |
s3_endpoint | string | "" | S3-совместимая конечная точка (напр. R2) |
s3_region | string | "" | Регион S3 (R2 использует «auto») |
s3_bucket | string | "" | Имя S3-бакета |
s3_access_key | string | "" | Ключ доступа S3 |
s3_secret_key | string | "" | Секретный ключ S3 |
restrict_uploads | boolean | false | Загружать могут только ключи из списка разрешённых |
Горячая перезагрузка (SIGHUP)
Отредактируйте файл и отправьте kill -HUP $(cat nostrfy.pid) — конфигурация перезагрузится без
перезапуска. Большинство настроек вступают в силу сразу; несколько зафиксированы при запуске:
| Применяется по SIGHUP | Требует перезапуска |
|---|
| relay.name, description, pubkey, contact, icon, post_policy, public_url | relay.private_key |
| reject_ephemeral, enabled_git, enabled_nip78_auth | relay.livekit_*, enabled_nips / disabled_nips |
| большая часть [limits] | api_host, trusted_proxies, metrics_enabled, ws_paths, database.*, размеры демона, лимиты, blossom.* |
[access] перезагрузкой не применяется — списки засеиваются один раз при запуске и затем управляются в процессе работы через NIP-86.
Журнал предупреждает, когда изменилась настройка, требующая перезапуска, а несколько захваченных при запуске настроек проверкой
перезагрузки не охватываются.
| Ошибка | Исправление |
|---|
| public_url не задан | задайте wss://... |
| host остался 127.0.0.1 | внешние клиенты не могут подключиться |
| private_key не задан при NIP-29 | выполните nostrfy genkey + перезапуск |
| restrict_relay true при пустом списке разрешённых | все заблокированы |
| изменили ключи только-для-перезапуска и послали лишь SIGHUP | используйте nostrfy restart |