Устранение неполадок
Ошибки, с которыми вы столкнётесь чаще всего, — порты, права, TLS, отсутствующие NIP, публикация и тайм-ауты — с пошаговыми исправлениями.
Три вещи, которые нужно проверить в первую очередь:
nostrfy checkпроверяет конфигурацию (большинство ошибок — это ошибки в конфигурации).tail -f nostrfy.logпоказывает журнал — причина почти всегда там.nostrfy restartкорректно перезапускает демона.
Не запускается
error: cannot bind to 0.0.0.0:80: Permission denied
Причина: порт 80 может занимать только root.
Исправление: запустите с sudo или смените порт, например на 8080.
# Смените port = 8080 в файле конфигурации, затем:
nostrfy --config nostrfy.toml starterror: cannot bind to ...: Address already in use
Причина: другой процесс (старый nostrfy или другой сервер) уже использует этот порт.
Исправление:
ss -tlnp | grep :8080# Если nostrfy запущен, перезапустите его
nostrfy --config nostrfy.toml restartalready running (pid 1234); use 'nostrfy stop' or 'nostrfy restart'
Причина: nostrfy уже запущен; start отказывается запускать второй экземпляр.
Исправление: используйте nostrfy restart или просто используйте уже работающий экземпляр.
nostrfy stop зависает / did not stop in time
Причина: демон завис или не отвечает.
Исправление:
ps aux | grep nostrfy
kill -9 <PID>
# Удалите устаревший pid-файл, если он есть
rm -f nostrfy.piderror: invalid nostrfy.toml: TOML parse error
Причина: файл конфигурации — некорректный TOML. Типичные ошибки: забытые кавычки вокруг строки или дважды записанный один и тот же ключ.
Исправление: сообщение об ошибке содержит номер строки. Проверьте и исправьте эту строку.
# Правильные примеры
name = "my relay" # строки — в кавычках "
port = 8080 # числа — без кавычек
enabled_nips = [1, 50] # списки — в квадратных скобках [ ]error: cannot read nostrfy.toml: No such file or directory
Причина: файл конфигурации не существует.
Исправление:
nostrfy --config nostrfy.toml initerror: relay.private_key is not a valid secp256k1 secret key
Причина: relay.private_key — невалидный 64-символьный hex-ключ.
Исправление: выполните nostrfy genkey, чтобы сгенерировать корректный ключ (или задайте private_key = "").
Много предупреждений в журнале при запуске
Строки журнала [WARN] сообщают о проблемах конфигурации. Основные:
| Предупреждение | Значение и исправление |
|---|---|
relay.public_url is empty and server.host is "0.0.0.0"... | public_url не задан — NIP-42 auth, NIP-62 vanish и NIP-98 admin auth не будут работать. Задайте wss://your-public-url. |
relay.private_key is empty while NIP-29 is enabled... | Группам нужен секретный ключ. Выполните nostrfy genkey. |
unknown config key [relay].software is ignored | Неиспользуемый устаревший ключ (или опечатка) в конфигурации. Проверьте имя ключа. |
unknown config section [serve] is ignored | Опечатка в имени секции (например, [serve] вместо [server]). Исправьте её. |
relay.require_auth is true but relay.send_auth_challenge is false... | Такая комбинация блокирует всех. Измените один из двух параметров. |
relay.require_pow = 64 ... practically unmineable | Требование PoW настолько высокое, что никто не может публиковать. Понизьте require_pow. |
Не подключается или работает странно
Клиент получает connection refused
Причина: релей не запущен или брандмауэр блокирует порт.
Исправление:
curl http://127.0.0.1:8080/health
# Снаружи (через IP/порт сервера)
curl http://YOUR_SERVER_IP:8080/health
# Проверьте брандмауэр (например: ufw)
sudo ufw status
# Откройте порт при необходимости
sudo ufw allow 8080Внешние клиенты не подключаются, локальные — да
Причина: server.host всё ещё 127.0.0.1 (по умолчанию), который принимает только локальные подключения.
Исправление: задайте host = "0.0.0.0" в конфигурации и перезапустите.
Не подключается через туннель Cloudflare
При использовании Cloudflare Tunnel:
- Релей работает по обычному HTTP; Cloudflare терминирует TLS, поэтому клиенты используют
wss://. Задайтеpublic_url = "wss://..."на релее (тогда заработает NIP-42 auth). - Cloudflare добавляет заголовок
X-Forwarded-Proto. nostrfy одинаково трактует значенияws/wss/http/https, поэтому дополнительная настройка обычно не нужна.
error: message too large, и соединение закрывается
Причина: одно сообщение превышает max_ws_message_bytes (по умолчанию 1 МБ).
Исправление: увеличьте limits.max_ws_message_bytes, если нужны более крупные события, — но проверьте и собственные лимиты клиента.
Ошибки too many subscriptions / too many filters
Причина: достигнуты лимиты на подключения (подписок по умолчанию 20, фильтров по умолчанию 20).
Исправление: увеличьте limits.max_subscriptions / limits.max_filters (и проверьте настройки клиента).
Новые подключения отклоняются под нагрузкой
Причина: достигнут max_connections (по умолчанию 10000), сработал лимит на IP
(max_connections_per_ip, по умолчанию 64) или лимит скорости подключений в секунду на IP
(max_connections_per_sec_per_ip) отклонил всплеск. Лимиты применяются к каждому подключению — и WebSocket, и обычному HTTP.
Исправление: проверьте и настройте параметры. max_connections_per_ip = 0 отключает лимит на IP; max_connections_per_sec_per_ip = 0 отключает лимит скорости. Эти три настройки требуют перезапуска.
Соединения разрываются через некоторое время
Причина: если задан ws_idle_timeout_secs, простаивающие соединения закрываются. Здоровые клиенты отвечают PONG на PING релея и остаются подключёнными; удаляются только мёртвые пиры.
Исправление: это задумано — по умолчанию 300 секунд. Задайте ws_idle_timeout_secs = 0, чтобы полностью отключить.
Подписка завершается с CLOSED ... response too large
Причина: сохранённые события одного REQ превысили max_req_response_bytes (по умолчанию 32 МиБ). Бывает только при очень крупных событиях или очень широких фильтрах.
Исправление: сузьте фильтр (более строгие since / until, меньший limit) или увеличьте max_req_response_bytes (0 отключает бюджет).
NIP отсутствует в списке NIP-11 supported_nips
Причина: публикуемый список динамический — NIP скрывается, когда все определяемые им kinds отклонены: все они в blocked_kinds, ни один из них не в allowed_kinds, или эфемерные kinds отклонены через reject_ephemeral.
NIP-29/43/66 дополнительно требуют relay.private_key, а NIP-86 требует rpc.management_token или rpc.admin_pubkey.
Исправление: проверьте активные списки доступа — NIP-86 listallowedkinds показывает список разрешённых kind, а GET / сразу показывает действующий supported_nips.
Уберите блокирующий kind или настройку reject_ephemeral.
Ошибки при публикации
Когда публикация не удаётся, 4-й элемент сообщения OK объясняет причину. Самые частые:
| Ошибка | Значение и исправление |
|---|---|
invalid: signature verification failed | Недействительная подпись события (возможно, сломанный ключ клиента). |
invalid: content too large | Контент превышает max_content_bytes (по умолчанию 64K символов). Сократите его или увеличьте лимит. |
invalid: too many tags | Тегов больше, чем max_tags (по умолчанию 2000). |
invalid: event creation date is in the future | Метка времени слишком далеко в будущем (за пределами max_created_at_future_secs). |
mute: event contains secret key material | Контент или теги содержат строку, похожую на nsec. Никогда не публикуйте секретные ключи. Удалите строку, и событие будет принято. |
duplicate: event already stored | Такое же событие уже сохранено (нормально). |
blocked: pubkey not allowed | Публичный ключ забанен (banpubkey) или вне списка разрешённых. |
blocked: kind not allowed | Этот kind запрещён. |
rate-limited: too many events | Публичный ключ превысил max_events_per_min_per_pubkey (скользящее 60-секундное окно). Подождите минуту и повторите, либо увеличьте/отключите лимит. |
blocked: event has been banned | ID события забанен. |
blocked: event has been deleted | Повторная публикация удалённого события. |
auth-required: ... | Требуется аутентификация (когда включён relay.require_auth). |
restricted: your account is too new | Аккаунт создан в пределах new_pubkey_min_age_secs. Подождите и повторите. |
restricted: unknown group | Группа не существует (сначала создайте её). |
restricted: this group is closed | Группа closed; запросы на вступление без пригласительного кода не удовлетворяются. |
Файловый сервер Blossom
Загрузка завершается с ошибкой 401
Событие авторизации загрузки (kind 24242) отклонено. Проверьте, что:
- тег
expirationтокена присутствует и задан как unix-метка в будущем, - для upload/media/delete токен несёт тег
xс sha256 блоба, - тег
server(если есть) точно называет настроенныйblossom.host(только hostname, без схемы/пути), - токен подписан в последние 10 минут (окно свежести против повторов),
- и ключ подписи принадлежит самому загрузчику.
Загрузка завершается с ошибкой 403
Задано blossom.restrict_uploads = true, и публичного ключа нет в списке разрешённых — добавьте его командой nostrfy blossom allow npub1... (демон перезагрузится автоматически). Если список выглядит неверно, nostrfy blossom list покажет его.
Загрузка завершается с ошибкой 409
Клиент отправил заголовок X-SHA-256, который не совпадает с фактическим телом запроса (объявленный хеш вычислен по другим байтам — например, файл изменился между хешированием и отправкой).
Клиенты могут вообще опустить заголовок.
GET / на медиа-хосте отдаёт NIP-11 документ
Запрос не дошёл до релея с заголовком Blossom Host. Направьте media.example.com (или то, что задано как blossom.host) на тот же порт в обратном прокси, затем nostrfy restart.
Блоб отдаёт 404 сразу после загрузки
Файл адресуется по содержимому через SHA-256: запрашивайте его по точному хешу, возвращённому в ответе загрузки (/<sha256> или /<sha256>.<ext>). Несовпадение означает,
что клиент запросил другой хеш, чем отправленные байты.
Поиск, группы и auth
Поиск возвращает 0 результатов / неожиданные результаты
Поиск nostrfy совпадает по целым словам. Обратите внимание, что:
search = "rust"совпадает с событиями, содержащими слово «rust», но"ru"НЕ совпадает с «rust» как подстрока.- Ищутся только слова в контенте событий.
- Если
search_index = false, поиск всё равно работает, но медленнее. - Если NIP-50 отключён (
disabled_nips = [50]),searchигнорируется (отправляется NOTICE).
Метаданные групп (39000-39005) не генерируются
Причина: relay.private_key не задан. Снапшоты групп подписываются собственным ключом релея, поэтому без него ничего не генерируется.
Исправление:
nostrfy --config nostrfy.toml genkey
nostrfy --config nostrfy.toml restartrestricted: unknown group отклоняет события групп
Причина: группа не существует. В NIP-29 события модерации и запросы на вступление (9021) не могут быть направлены группе до её создания (kind 9007).
Исправление: сначала создайте группу событием 9007.
restricted: you are not an admin of this group
Причина: модерация (добавление участников и т. д.) требует администратора (участника с ролью). Создатель — администратор.
Исправление: попросите администратора выдать вам роль или создайте собственную группу.
restricted: this group is closed
Причина: группа closed; запросы на вступление без пригласительного кода не одобряются автоматически.
Исправление: попросите у администратора пригласительный код (9009) и вступайте с тегом code.
Случайно покинули группу, или в группе нет администраторов
Причина: запросы на выход NIP-29 (kind 9022) уважаются для любого участника — включая последнего администратора группы, после ухода которого администраторов не остаётся. Без администратора никто больше не может отправлять события модерации (9000/9001/9002/9008).
Исправление: подпишите событие модерации собственным ключом релея (relay.private_key,
публичный ключ, публикуемый как NIP-11 self). Согласно NIP-29, события модерации могут исходить от «мастер-ключа релея или … администраторов групп», поэтому релей принимает модерацию групп, подписанную собственным ключом, даже когда в группе нет администраторов. Например, восстановите администратора с kind:9000:
{
"kind": 9000,
"pubkey": "<relay self pubkey>",
"tags": [["h", "<group-id>"], ["p", "<member-hex>", "admin"]]
}Подпишите и опубликуйте его ключом релея. Либо удалите группу подписанным релеем kind:9008 (её сохранённые события очищаются) и создайте заново с kind:9007.
Для этого восстановления нужен настроенный relay.private_key.
Защищённые события отклоняются с auth-required
Причина: защищённые события NIP-70 (с тегом -) могут публиковаться только аутентифицированным автором на том же соединении.
Исправление: включите NIP-42 auth в клиенте перед публикацией.
AUTH (NIP-42) возвращает false
Частые причины:
relay.public_urlне задан или неверен — тегrelayсобытия AUTH не совпадает с URL релея. Задайтеwss://...и перезапустите.- Устаревший challenge — вы отправили AUTH на другом соединении или повторно использовали старый challenge.
- Часы клиента сбиты —
created_atсобытия AUTH должен быть в пределах ±10 минут от текущего времени.
API управления NIP-86 возвращает 401 unauthorized
Причина: отсутствуют или неверны учётные данные.
Исправление:
- Задайте
management_tokenи отправляйтеAuthorization: Bearer <token>. - Или задайте
admin_pubkeyи отправьте NIP-98 auth-событие (тегuдолжен точно совпадать с URL релея; тегpayloadобязателен). - Если не задано ни то, ни другое, API управления полностью отключён.
Auth-события NIP-98 отклоняются из-за другой схемы или порта
Спецификация NIP-98 требует, чтобы тег u был в точности тем же, что и абсолютный URL запроса, поэтому nostrfy выводит ожидаемый URL из relay.public_url: его authority плюс HTTP-схема, отображённая из WebSocket-схемы (wss:// → https://, ws:// → http://, nostr+ отбрасывается). Без public_url релей ожидает обычный http://host:port, который он обслуживает. Тег с другой схемой, другим/опущенным портом либо другим путём или запросом отклоняется — задайте relay.public_url как публичный адрес, который подписывают клиенты. Каждое auth-событие также одноразовое: повтор той же строки Authorization в пределах 60-секундного окна валидности отклоняется.
База данных и диск
database map is full: increase database.max_map_size
Причина: достигнут потолок memory-map LMDB (по умолчанию 1 ТБ виртуального адресного пространства; реальное использование диска растёт с данными) — фактически база данных переполнена.
Исправление: увеличьте database.max_map_size и перезапустите.
disk is full: refusing to commit N events
Причина: менее 32 МБ свободного места на диске. Записи останавливаются (для защиты данных); чтения продолжаются.
Исправление: освободите место на диске. Записи возобновятся автоматически, как только место появится.
(df -h /path/to/data)
nostrfy check сообщает map_size must not exceed max_map_size
Причина: database.map_size больше, чем max_map_size.
Исправление: задайте map_size на уровне или ниже max_map_size (значений по умолчанию достаточно).
Проверка размера базы данных
curl http://127.0.0.1:8080/relay/stats
# => "db_size_bytes" в байтахРезервное копирование / перенос базы данных
Все данные находятся в каталоге database.path. Остановите релей перед копированием (копирование живой базы может её повредить).
nostrfy --config nostrfy.toml stop
cp -a ./data ./data-backup
# Также скопируйте [blossom].local_path при локальном хранилище Blossom.
nostrfy --config nostrfy.toml startРабота демона
nostrfy stats говорит nostrfy is not running (no stats file)
Причина: файл статистики не существует — демон не запущен или запущен менее нескольких секунд назад.
Исправление: выполните nostrfy start, подождите несколько секунд и попробуйте снова.
Журнал растёт без ограничений
Причина: max_log_size_bytes равен 0 (ротация отключена).
Исправление: задайте max_log_size_bytes = 52428800 (50 МБ) и max_log_files = 5. Ротация автоматическая.
Изменения конфигурации не применяются после reload
Причина: вы перезагрузили (SIGHUP) настройки, фиксированные при старте: private_key, api_host, metrics_enabled, настройки LiveKit и списки включения/отключения NIP.
Исправление: используйте nostrfy restart. В журнале в этом случае есть предупреждение «a restart is required».
Релей сам завершается
Причина: машина перезагрузилась или у релея закончилась память (OOM).
Исправление:
- Проверьте конец журнала:
tail -50 nostrfy.log. - Проверьте, перезагружалась ли машина:
uptime(очень короткое время работы означает перезагрузку). - Проверьте память:
free -h. - Запустите релей снова:
nostrfy start.
systemd не может запустить релей на порту 80
Systemd-сервис, работающий от root, может занимать порт 80. Если в User= задан обычный пользователь,
либо используйте более высокий порт (например, 8080), либо добавьте AmbientCapabilities=CAP_NET_BIND_SERVICE в юнит.
Всё ещё не решено?
- Проверьте журнал:
tail -100 nostrfy.log— там обычно названа прямая причина. - Перепроверьте конфигурацию:
nostrfy check— показывает предупреждения и ошибки. - Соберите детали воспроизведения: что вы делали, какой клиент, какая точная ошибка.
- Спросите в репозитории проекта: https://github.com/iqbqioza/nostrfy — при подаче issue включите шаги воспроизведения и журнал.