トラブルシューティング

発生しやすいエラー(ポート、権限、TLS、不足している NIP、パブリッシュ、タイムアウト)と段階的な修正方法をまとめています。

最初に確認すべき3つのこと:

  • nostrfy check は設定を検証します(ほとんどのエラーは設定ミスです)。
  • tail -f nostrfy.log でログを確認します — 原因はほぼ必ずそこにあります。
  • nostrfy restart はデーモンをクリーンに再起動します。

起動できない

error: cannot bind to 0.0.0.0:80: Permission denied

原因: ポート 80 は root のみがバインドできます。

修正: sudo で実行するか、ポート 8080 のような高いポートに変更してください。

sh
# 設定ファイルで port = 8080 を変更してから実行します:
nostrfy --config nostrfy.toml start

error: cannot bind to ...: Address already in use

原因: 別のプロセス(古い nostrfy や別のサーバー)がすでにそのポートを使用しています。

修正:

sh
ss -tlnp | grep :8080
sh
# nostrfy が実行中の場合は再起動します
nostrfy --config nostrfy.toml restart

already running (pid 1234); use 'nostrfy stop' or 'nostrfy restart'

原因: nostrfy はすでに実行中です。start は2つ目のインスタンスの起動を拒否します。

修正: nostrfy restart を使うか、実行中のインスタンスをそのまま使ってください。

nostrfy stop がハングする / did not stop in time

原因: デーモンが停止しているか、応答していません。

修正:

sh
ps aux | grep nostrfy
kill -9 <PID>
# 古い pid ファイルがあれば削除します
rm -f nostrfy.pid

error: invalid nostrfy.toml: TOML parse error

原因: 設定ファイルが正しい TOML ではありません。よくあるミス:文字列の引用符の付け忘れや、同じキーの重複です。

修正: エラーメッセージに行番号が含まれています。その行を確認して修正してください。

toml
# 正しい例:
name = "my relay"        # 文字列は " で囲みます
port = 8080              # 数値はそのまま書きます
enabled_nips = [1, 50]   # リストは [ ] で囲みます

error: cannot read nostrfy.toml: No such file or directory

原因: 設定ファイルが存在しません。

修正:

sh
nostrfy --config nostrfy.toml init

error: relay.private_key is not a valid secp256k1 secret key

原因: relay.private_key が有効な64文字の16進キーではありません。

修正: nostrfy genkey を実行して正しいキーを生成してください(または private_key = "" を設定します)。

起動時にログに大量の警告が出る

[WARN] ログ行は設定上の問題を知らせます。主なもの:

警告意味と修正方法
relay.public_url is empty and server.host is "0.0.0.0"...public_url が未設定です — NIP-42 認証、NIP-62 vanish、NIP-98 管理者認証が動作しません。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セクション名のタイプミスです(例:[server] ではなく [serve])。修正してください。
relay.require_auth is true but relay.send_auth_challenge is false...この組み合わせでは全員が締め出されます。どちらか一方を変更してください。
relay.require_pow = 64 ... practically unmineablePoW 要件が高すぎて誰も投稿できません。require_pow を下げてください。

接続できない・動作がおかしい

クライアントが connection refused を受け取る

原因: リレーが実行されていないか、ファイアウォールがポートをブロックしています。

修正:

sh
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 認証が動作するようになります)。
  • Cloudflare は X-Forwarded-Proto ヘッダーを追加します。nostrfy は ws / wss / http / https の値を同じものとして扱うため、通常は追加設定は不要です。

error: message too large で接続が切れる

原因: 単一メッセージが max_ws_message_bytes(既定 1 MB)を超えています。

修正: より大きなイベントが必要なら 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)が働いたか、秒間接続レート制限 (max_connections_per_sec_per_ip)がバーストを拒否しました。これらの上限は WebSocket とプレーン HTTP のすべての接続に適用されます。

修正: 設定を見直して調整してください。max_connections_per_ip = 0 で IP ごとの上限を無効化し、max_connections_per_sec_per_ip = 0 でレート制限を無効化します。これら3つの設定には再起動が必要です。

しばらくすると接続が切れる

原因: ws_idle_timeout_secs が設定されていると、アイドル接続は閉じられます。正常なクライアントはリレーの PING に PONG で応答して接続を維持し、死んだピアのみが刈り取られます。

修正: これは意図的な動作です — 既定は 300 秒です。完全に無効にするには ws_idle_timeout_secs = 0 に設定してください。

サブスクリプションが CLOSED ... response too large で終わる

原因: 1つの REQ の保存済みイベントが max_req_response_bytes(既定 32 MiB)を超えました。非常に大きなイベントや非常に広いフィルターでのみ発生します。

修正: フィルターを狭めてください(since / until を厳しく、limit を小さく)か、max_req_response_bytes を引き上げてください(0 で上限を無効化)。

NIP-11 の supported_nips 一覧に NIP がない

原因: 公開リストは動的です — 定義する kind がすべて拒否されると NIP は非表示になります:すべてが blocked_kinds にある、allowed_kinds に含まれていない、または reject_ephemeral で一時的 kind が拒否されている場合です。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 設定を取り除いてください。

パブリッシュ時のエラー

パブリッシュに失敗した場合、OK メッセージの4番目の要素が理由を示します。よくあるもの:

エラー意味と修正方法
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秒のスライディングウィンドウ)。1分待って再試行するか、制限を引き上げ/無効化してください。
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 ではトークンが blob の sha256 を持つ x タグを含んでいること、
  • server タグ(ある場合)が設定済みの blossom.host と正確に一致していること(ホスト名のみ、スキームやパスなし)、
  • トークンが過去 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 してください。

アップロード直後に blob が 404 になる

ファイルは SHA-256 によるコンテンツアドレスです。アップロード応答で返された正確なハッシュで取得してください(/<sha256> または /<sha256>.<ext>)。不一致は、送信したバイト列と異なるハッシュをクライアントが要求したことを意味します。

検索・グループ・認証

検索結果が 0 件になる / 想定外の結果になる

nostrfy の検索は単語単位で一致します。注意点:

  • search = "rust" は「rust」という単語を含むイベントに一致しますが、"ru" は「rust」の部分文字列としては一致しません。
  • 検索対象はイベント本文内の単語のみです。
  • search_index = false でも検索は動作しますが遅くなります。
  • NIP-50 が無効な場合(disabled_nips = [50])、search は無視されます(NOTICE が送られます)。

グループメタデータ(39000-39005)が生成されない

原因: relay.private_key が未設定です。グループスナップショットはリレー自身のキーで署名されるため、それがないと何も生成されません。

修正:

sh
nostrfy --config nostrfy.toml genkey
nostrfy --config nostrfy.toml restart

restricted: 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 で管理者を復元します:

json
{
  "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(NIP-42)が false を返す

よくある原因:

  1. relay.public_url が未設定か誤っている — AUTH イベントの relay タグがリレーの URL と一致しません。wss://... を設定して再起動してください。
  2. 古いチャレンジ — 別の接続で AUTH を送ったか、古いチャレンジを再利用しました。
  3. クライアントの時計がずれている — AUTH イベントの created_at は現在時刻の ±10 分以内である必要があります。

NIP-86 管理 API が 401 unauthorized を返す

原因: 認証情報がないか誤っています。

修正:

  • management_token を設定し、Authorization: Bearer <token> を送ります。
  • または admin_pubkey を設定し、NIP-98 認証イベントを送ります(u タグはリレー URL と完全一致が必要で、payload タグが必須です)。
  • どちらも未設定の場合、管理 API は完全に無効です。

NIP-98 認証イベントがスキームやポートの違いで拒否される

NIP-98 仕様では u タグは絶対リクエスト URL と完全一致でなければならず、nostrfy は期待 URL を relay.public_url から導出します:WebSocket スキームに対応する HTTP スキームへの対応付けによる権威部分(wss:// → https://、ws:// → http://、nostr+ 除去)。public_url がない場合、リレーは提供中のプレーンな http://host:port を期待します。異なるスキーム・異なる/省略されたポート・異なるパスやクエリのタグは拒否されます — クライアントが署名する公開アドレスを relay.public_url に設定してください。各認証イベントは使い捨てでもあります:60秒の有効期間内に同じ Authorization ヘッダーを再送すると拒否されます。

データベースとディスク

database map is full: increase database.max_map_size

原因: LMDB のメモリマップ上限(既定で仮想アドレス空間 1 TB。実際のディスク使用量はデータとともに増加)に達しました — 実質的にデータベースがいっぱいです。

修正: database.max_map_size を引き上げて再起動してください。

disk is full: refusing to commit N events

原因: 空きディスク容量が 32 MB 未満です。書き込みは停止します(データを保護するため)。読み取りは継続します。

修正: ディスク容量を空けてください。空きができれば書き込みは自動的に再開します。(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 以下に設定してください(既定値で問題ありません)。

データベースサイズの確認

sh
curl http://127.0.0.1:8080/relay/stats
# => "db_size_bytes" をバイト単位で取得します

データベースのバックアップ / 移行

すべてのデータは database.path ディレクトリにあります。コピー前にリレーを停止してください(稼働中のデータベースのコピーは破損する恐れがあります)。

sh
nostrfy --config nostrfy.toml stop
cp -a ./data ./data-backup
# ローカルの Blossom ストレージ使用時は [blossom].local_path もバックアップします。
nostrfy --config nostrfy.toml start

デーモンの運用

nostrfy stats が nostrfy is not running (no stats file) と表示する

原因: stats ファイルが存在しません — デーモンが実行されていないか、起動から数秒以内です。

修正: nostrfy start を実行し、数秒待ってから再試行してください。

ログが際限なく増える

原因: max_log_size_bytes が 0 です(ローテーション無効)。

修正: max_log_size_bytes = 52428800(50 MB)と max_log_files = 5 を設定してください。ローテーションは自動です。

リロード後に設定変更が反映されない

原因: 起動時に固定される設定をリロード(SIGHUP)しました:private_key、api_host、metrics_enabled、LiveKit 設定、NIP 有効/無効リストです。

修正: nostrfy restart を使ってください。この場合ログに「a restart is required」という警告が出ます。

リレーが勝手に停止する

原因: マシンが再起動したか、リレーがメモリ不足(OOM)になりました。

修正:

  1. ログの末尾を確認:tail -50 nostrfy.log。
  2. マシンが再起動したか確認:uptime(稼働時間が非常に短ければ再起動しています)。
  3. メモリを確認:free -h。
  4. リレーを再起動:nostrfy start。
ヒント
起動時に nostrfy を自動起動するには、リレーの起動コマンドを ExecStart とする systemd サービスとして登録してください。

systemd がポート 80 でリレーを起動できない

root で動作する systemd サービスはポート 80 をバインドできます。User= に一般ユーザーを設定した場合は、高いポート(例:8080)を使うか、ユニットに AmbientCapabilities=CAP_NET_BIND_SERVICE を追加してください。

まだ解決しない場合

  1. ログを確認:tail -100 nostrfy.log — 直接の原因が書かれていることが多いです。
  2. 設定を再検証:nostrfy check — 警告とエラーを表示します。
  3. 再現情報を集める:何をしていたか、どのクライアントか、正確なエラーは何か。
  4. プロジェクトリポジトリで質問する: https://github.com/iqbqioza/nostrfy — issue を立てる際は再現手順とログを含めてください。