疑難排解
你最可能遇到的錯誤 — 連接埠、權限、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 字元十六進位金鑰。
修正:執行 nostrfy genkey 產生正確的金鑰(或設定 private_key = "")。
啟動時日誌中有大量警告
[WARN] 日誌行告訴你設定問題。主要的:
| 警告 | 意義與修正 |
|---|---|
relay.public_url is empty and server.host is "0.0.0.0"... | 未設定 public_url — NIP-42 認證、NIP-62 消除與 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 | 區段名稱拼寫錯誤(例如 [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 Tunnel 連線
使用 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 停用速率限制。這三項
設定需要重新啟動。
連線一段時間後中斷
原因:如果設定了 ws_idle_timeout_secs,閒置連線會被關閉。
健康的用戶端會用 PONG 回應中繼的 PING 並保持連線;只有死掉的一端會被清理。
修正:這是有意為之 — 預設 300 秒。設定 ws_idle_timeout_secs = 0 完全停用它。
訂閱以 CLOSED ... response too large 結束
原因:一個 REQ 的已儲存事件超過了 max_req_response_bytes (預設 32 MiB)。只在事件非常大或過濾器非常寬時發生。
修正:縮小過濾器(更嚴格的 since/until、更低的 limit)或提高 max_req_response_bytes(0 停用預算)。
NIP-11 supported_nips 清單中缺少某個 NIP
原因:公佈的清單是動態的 — 當某個 NIP 定義的所有類型都被
拒絕時它會被隱藏:它們都在 blocked_kinds 中、都不在 allowed_kinds 中,或它們是 reject_ephemeral 拒絕的臨時類型。
NIP-29/43/66 還需要 relay.private_key,NIP-86 需要 rpc.management_token 或 rpc.admin_pubkey。
修正:檢查使用中的存取清單 — NIP-86 listallowedkinds 顯示
類型允許清單,GET / 立即顯示生效的 supported_nips。
移除封鎖的類型或 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 | 此類型被禁止。 |
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,權杖帶有包含 blob 的 sha256 的
x標籤, server標籤(如果存在)正好是設定的blossom.host(僅主機名稱,無 scheme/path),- 權杖是在最近 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。群組快照由
中繼自己的金鑰簽章,因此沒有它就不會產生任何東西。
修正:
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(NIP-42)傳回 false
常見原因:
- 未設定或錯誤設定
relay.public_url— AUTH 事件的relay標籤與 中繼的 URL 不符。設定wss://...並重新啟動。 - 挑戰過期 — 你在不同的連線上傳送了 AUTH,或重用了舊的挑戰。
- 用戶端時鐘偏差 — AUTH 事件的
created_at必須在 現在的 ±10 分鐘內。
NIP-86 管理 API 傳回 401 unauthorized
原因:憑證缺失或錯誤。
修正:
- 設定
management_token並傳送Authorization: Bearer <token>。 - 或設定
admin_pubkey並傳送 NIP-98 認證事件(u標籤必須與 中繼 URL 完全相符;需要payload標籤)。 - 如果兩者都未設定,管理 API 完全停用。
NIP-98 認證事件因 scheme 或連接埠不同被拒絕
NIP-98 規範說 u 標籤必須與絕對請求 URL 完全相同,因此
nostrfy 從 relay.public_url 推導期望的 URL:其 authority 加上
從 WebSocket scheme 映射的 HTTP scheme(wss:// → https://, ws:// → http://,去掉 nostr+)。沒有 public_url 時,中繼期望它提供的一般 http://host:port。帶有
其他 scheme、不同/省略連接埠,或不同路徑或查詢的標籤會被拒絕 — 將 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(預設值
就沒問題)。
檢查資料庫大小
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 儲存時,也要備份 [blossom].local_path。
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 MB)與 max_log_files = 5。輪替自動進行。
重載後設定變更沒有生效
原因:你重載(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 連接埠啟動中繼
以 root 執行的 systemd 服務可以綁定 80 連接埠。如果你把 User= 設為一般使用者,
要嘛使用更高的連接埠(例如 8080),要嘛向單元加入 AmbientCapabilities=CAP_NET_BIND_SERVICE。
仍未解決?
- 檢查日誌:
tail -100 nostrfy.log— 它通常會指出直接 原因。 - 重新驗證設定:
nostrfy check— 顯示警告與錯誤。 - 收集重現細節:你在做什麼、哪個用戶端、確切的錯誤。
- 在專案倉庫提問: https://github.com/iqbqioza/nostrfy — 提交 issue 時,附上重現步驟與日誌。