StackTraces
OpenSearch已驗證

OpenSearch 預設 TLS 下用 http 訪問 9200 報 Empty reply from server

@debug_master今天更新閱讀 6 min00

OpenSearch 的 demo security 設定預設啟用,9200 REST 層只走 TLS。用 http:// 訪問時服務端 TLS 握手失敗、直接關閉連接,curl 收不到任何響應字節,報 curl: (52) Empty reply from server。改用 https:// 並帶上 -k 和憑據即可。適用 Docker 鏡像預設設定下的 OpenSearch 2.12+ 全版本。

Issue & Env(案發現場與環境)

  • 業務場景:用官方 Docker 鏡像起單節點 OpenSearch,按 Elasticsearch 習慣先 curl http://localhost:9200 探活——連接秒建、不報錯,但響應是空的。
  • 環境:OpenSearch 3.9.0 stable,鏡像 opensearchproject/opensearch:latest,demo security 設定預設啟用(TLS + 自簽證書),macOS / Linux / Docker 均可復現。
  • 關鍵區分:不是超時,也不是拒絕連接。TCP 連上了,服務端主動斷開,一個字節都沒回;補 -u 憑據也沒用,因為請求根本沒進 HTTP 層。

StackTrace(堆疊日誌)

客戶端側只有一行,信息量很少:

curl http://localhost:9200
# curl: (52) Empty reply from server

真正的成因在服務端日誌裡。OpenSearch 官方論壇帖 #20152(OpenSearch 2.15,Helm 部署)記錄了完整現場:

[opensearch@opensearch-cluster-master-0 ~]$ curl http://opensearch-cluster-master:9200 --insecure -u "admin:Moto1sBe\$t"
curl: (52) Empty reply from server
[2024-07-05T09:05:30,790][ERROR][o.o.h.n.s.SecureNetty4HttpServerTransport] [opensearch-cluster-master-0] Exception during establishing a SSL connection: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 474554202f20485454502f312e310d0a486f73743a206c6f63616c686f73743a393230300d0a557365722d4167656e743a206375726c2f382e352e300d0a4163636570743a202a2f2a0d0a0d0a

那串十六進制不是隨機字節,解碼出來恰好是 curl 發出的明文 HTTP 請求:

echo "474554202f20485454502f312e310d0a" | xxd -r -p
# GET / HTTP/1.1

Reproduce(復現程式碼)

最小復現——官方鏡像預設設定啟動單節點:

docker run -d -p 9200:9200 -p 9600:9600 \
  -e "discovery.type=single-node" \
  -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=Devfix@2026" \
  opensearchproject/opensearch:latest

2.12+ 必須傳 OPENSEARCH_INITIAL_ADMIN_PASSWORD,至少 8 位且大小寫、數字、特殊字符各一,否則容器直接退出。等啟動完成後分別探測:

# 明文 http:连接建立,空响应断开
curl http://localhost:9200
# curl: (52) Empty reply from server

# 补上凭据,结果不变——问题不在认证层
curl -u admin:Devfix@2026 http://localhost:9200
# curl: (52) Empty reply from server

# 协议换成 https,立刻正常
curl -sk -u admin:Devfix@2026 "https://localhost:9200"

Root Cause(根因分析)

TLS 端口收到明文請求

demo security 設定把 plugins.security.ssl.http.enabled 置為 true,官方 security configuration 文檔裡就是這個鍵。9200 端口還是那個端口,但 Netty 的 SslHandler 擋在前面:連接建立後服務端期待的第一段數據是 TLS 握手記錄,不是 HTTP 報文。

curl 用 http:// 發出明文 GET / HTTP/1.1,服務端按 TLS 記錄格式解析失敗,拋 NotSslRecordException 後直接關閉連接。日誌裡那串 hex 正是被拒收的明文請求本身。

(52) 的語義

curl 錯誤碼 52 對應 CURLE_GOT_NOTHING:TCP 連接成功建立,但服務端在關閉前沒發出任何響應字節。和幾個相近錯誤區分開:

  • curl: (7) Failed to connect:端口沒監聽或被防火牆攔截,連接層就失敗;
  • curl: (28) Operation timed out:包被黑洞,等不到響應;
  • curl: (52) Empty reply from server:連上了、握手失敗、空著斷開。

認證不是本案的鍋

看到 (52) 很容易聯想到“沒傳憑據”。缺憑據的場景是 TLS 成功後返回 401 JSON,有完整響應體。本案請求連 HTTP 協議棧都沒進去,-u 和 --insecure 都救不了,解法只能在協議層:換 https。

The Fix(解決方案)

方案一:改用 https(推薦)

curl -sk -u admin:Devfix@2026 "https://localhost:9200"

-k 跳過自簽證書校驗,僅適合本地體驗。生產環境按官方文檔替換 demo 證書,用 --cacert root-ca.pem 指定 CA,不再加 -k。

方案二:禁用 security 插件(僅限本地體驗)

docker run -d -p 9200:9200 \
  -e "discovery.type=single-node" \
  -e "DISABLE_SECURITY_PLUGIN=true" \
  opensearchproject/opensearch:latest

curl http://localhost:9200

禁用後 9200 回到明文 HTTP。代價是沒有認證和授權,所有索引公開讀寫,不要暴露在任何不受控網絡上。

驗證修復

curl -sk -o /dev/null -w "%{http_code}\n" -u admin:Devfix@2026 "https://localhost:9200"
# 期望输出:200

客戶端 SDK 同理

opensearch-py、Java 客戶端等預設仍按明文 http 連接,啟用 security 後要在設定裡顯式打開 https、傳 basic auth 或 CA 證書,否則報錯形態相同——空響應或連接被重置。

注意事項

  • 本地部署的完整流程和其餘常見卡點,見 從零跑通 OpenSearch。
  • OpenSearch Dashboards 連的是同一個 9200,OPENSEARCH_HOSTS 也要寫 https:// 並處理證書,否則 Dashboards 同樣連不上。

References(參考來源)

最後更新於 2026-10-17

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法