在構建本地或云端搜索引擎系統時,EasySearch 憑借其輕量、高性能、易部署等優勢,逐漸成為眾多開發者和技術愛好者的首選。但在實際部署過程中,如何借助 Nginx 為 EasySearch 提供高效、穩定且安全的訪問入口,尤其是在身份認證方面,仍然是一個關鍵技術環節。
本教程將圍繞 Basic Auth 認證機制展開,系統講解如何通過 Nginx 實現安全防護、認證信息透傳等常見配置場景,幫助你在多種實際部署環境中快速搭建可靠的訪問控制機制。
無論你是在搭建家庭 NAS 服務,還是在企業環境中集成搜索引擎系統,本教程都能為你提供一套可落地、可復用的 Nginx 安全認證解決方案。。
下面是我的 Nginx 配置文件示例。我們通過 Docker 啟動 Nginx 容器,并將本地編寫好的配置文件掛載到容器中,從而實現自定義的反向代理和認證邏輯:
docker run -d \--name my-nginx \-p 80:80 \-v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf \nginx
default.conf配置如下:
server {listen 80;server_name localhost;# 根路徑可選配置,如果你要一個歡迎頁location / {return 200 'Nginx is running.\n';add_header Content-Type text/plain;}# 反向代理 EasySearch location /es/ {proxy_pass https://backend:9200/;# 修正請求頭proxy_http_version 1.1;# proxy_pass_request_headers on; ÷proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;# 如果需要保活連接proxy_set_header Connection "";# 可選:允許跨域訪問(用于前端 AJAX 調試)add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';add_header Access-Control-Allow-Headers 'Authorization,Content-Type';# proxy_set_header Authorization "Basic YWRtaW46MTIzNDU2";# 清理路徑前綴 `/es/`rewrite ^/es/(.*)$ /$1 break;}# 可選:靜態資源支持# location /static/ {# root /usr/share/nginx/html;# }
}
🌐 配置整體結構
server {listen 80;server_name localhost;
- 監聽端口:監聽本地
80
端口(HTTP 默認端口) - 服務名稱:用于匹配請求的
Host
,這里是localhost
🎉 歡迎頁(根路徑 /
)
location / {return 200 'Nginx is running.\n';add_header Content-Type text/plain;
}
- 請求
/
會返回純文本響應"Nginx is running."
,可用于驗證 Nginx 是否啟動正常。 add_header Content-Type text/plain
:指定響應內容為純文本。
🔁 /es/
代理 EasySearch 后端服務
🚚 請求頭處理
proxy_http_version 1.1;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header Connection "";
proxy_http_version 1.1
:確保代理使用 HTTP/1.1,支持長連接。Host
:保留原始請求的主機名。X-Real-IP
/X-Forwarded-For
:傳遞客戶端真實 IP。X-Forwarded-Proto
:傳遞原始協議(http / https)。Connection ""
:用于避免默認的keep-alive
設置引起錯誤(推薦保留)。
🔐 可選的認證頭(注釋中)
# proxy_set_header Authorization "Basic YWRtaW46MTIzNDU2";
- 可選開啟,用于將認證信息轉發到后端。
- 上面的字符串是
admin:123456
的 base64 編碼。可以根據需要開啟。
🌍 CORS 設置(跨域)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Authorization,Content-Type';
- 允許任意源訪問(前端頁面可以跨域請求
/es/
)。 - 支持的方法:GET、POST、OPTIONS。
- 允許傳遞的請求頭:Authorization 和 Content-Type。
- ? 適用于 AJAX 調試、前后端分離等場景。
🔧 URL 重寫
rewrite ^/es/(.*)$ /$1 break;
- 移除
/es/
前綴,轉發給后端。例如:
用戶請求/es/_cat/indices
實際轉發到/cat/indices
。 break
表示在當前 location 中中止后續重寫檢查。
📦 可選靜態資源(被注釋掉)
# location /static/ {
# root /usr/share/nginx/html;
# }
- 若開啟,可以直接通過
/static/xxx.js
訪問 Nginx 本地/usr/share/nginx/html/static/xxx.js
文件。
🔁 如果你想保留 /es/
前綴,則刪除 rewrite
行。
在啟動服務后,當我們通過瀏覽器訪問 Nginx 時,頁面會彈出身份驗證窗口。需要注意的是,這里的認證提示實際上來自后端的 EasySearch 服務,而非 Nginx 本身,說明請求中的認證信息未在 Nginx 層被處理或透傳,因此由 EasySearch 發起了再次認證的要求。
在輸入正確的用戶名和密碼后,我們可以看到 Nginx 成功代理請求,并返回了來自 EasySearch 的 API 響應,說明認證流程已順利通過,后端服務正常可用。
如果希望由 Nginx 代為完成 EasySearch 的身份驗證,也就是實現自動登錄的效果,可以在配置文件中添加如下指令,將認證信息通過 HTTP 頭部傳遞給后端:
proxy_set_header Authorization "Basic YWRtaW46YWRtaW4=";
其中,YWRtaW46YWRtaW4xMjM=
是使用 Base64 編碼后的 用戶名:密碼
字符串(例如 admin:admin
)。Nginx 在轉發請求時會自動攜帶該 Header,從而實現對 EasySearch 的自動認證。
需要注意的是,Nginx 的配置文件修改后不會自動生效。為了確保配置被正確加載,需在每次更改配置文件后重啟對應的容器服務。這是容器化部署中常見的操作流程,確保新配置被正確應用。
為了更直觀地觀察請求行為,我們使用了 Postman 進行測試。可以發現,即使在 Postman 中未顯式添加任何認證信息,依然能夠成功訪問 EasySearch 集群。這說明前端未輸入認證信息,但由于 Nginx 曾經緩存了認證狀態,或配置了自動透傳,導致后端依舊接收到了有效的認證頭,從而允許了訪問。
這種現象雖然在測試中提升了訪問便利性,但在實際部署中可能帶來安全風險,因此在生產環境中建議對認證流程進行嚴格控制,確保后端服務不會因為前端認證機制的疏漏而被繞過。
在一些教程中,常會提到一個名為 .htpasswd
的文件,它用于在 Nginx 層實現基本認證。當啟用該機制后,Nginx 會對所有訪問進行用戶身份驗證。
此時,是否將認證信息透傳給后端服務,則由 proxy_pass_request_headers
參數決定。該參數默認值為 on
,也就是說,當認證通過后,客戶端發送的 Authorization 頭部信息會被 Nginx 一并轉發給后端服務。
為了驗證這一行為,我編寫了一個簡單的 Flask 程序作為后端,用于觀察請求中的 Header 內容。在真正將請求代理至 EasySearch 之前,我先讓 Nginx 將請求反向代理到這個 Flask 應用,從而可以直觀地查看是否存在 Authorization 頭被透傳的情況。
from flask import Flask, request,abort
import base64
app = Flask(__name__)@app.route('/')
def hello_world():print("📥 Headers received from Nginx:")print("Host:", request.headers.get('Host'))print("X-Real-IP:", request.headers.get('X-Real-IP'))print("X-Forwarded-For:", request.headers.get('X-Forwarded-For'))print("X-Forwarded-Proto:", request.headers.get('X-Forwarded-Proto'))print(request.headers)auth_header = request.headers.get('Authorization')print("Authorization:", auth_header)if not auth_header or not auth_header.startswith('Basic '):abort(401, description="Missing or invalid Authorization header")# 解碼 base64encoded = auth_header.split(' ')[1]decoded = base64.b64decode(encoded).decode('utf-8') # e.g. admin:123456username, password = decoded.split(':', 1)print(username, password)return 'Hello World!'if __name__ == '__main__':app.run(host='0.0.0.0', port=8000,debug=True)
這個是flask的打印的結果.
Host: secure-nginx.orb.local
X-Real-IP: 192.168.215.1
X-Forwarded-For: 192.168.215.1
X-Forwarded-Proto: http
Host: secure-nginx.orb.local
X-Real-Ip: 192.168.215.1
X-Forwarded-For: 192.168.215.1
X-Forwarded-Proto: http
Authorization: Basic YWRtaW46YWRtaW4=
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8
Cookie: perf_dv6Tr4n=1Authorization: Basic YWRtaW46YWRtaW4=
admin admin
192.168.X.X - - [24/Apr/2025 15:55:59] "GET / HTTP/1.1" 200 -
為了解決雙重認證的問題,我們啟用了認證信息透傳的配置(默認的roxy_pass_request_headers on;)。啟用該配置后,用戶只需在訪問 Nginx 時進行一次手動身份驗證。Nginx 會將用戶提供的憑證通過 HTTP Header 透傳至后端的 EasySearch 服務,從而避免二次認證。當用戶直接訪問 EasySearch 時,依然需要單獨輸入憑證進行認證;但通過 Nginx 訪問時,只需在前端認證一次即可完成整個請求流程。
curl -k https://easysearch:9200 {"error":{"root_cause":[{"type":"security_exception","reason":"Missing authentication information for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"Security\" charset=\"UTF-8\""}}],"type":"security_exception","reason":"Missing authentication information for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"Security\" charset=\"UTF-8\""}},"status":401}?
-------curl -v -u "admin:admin" http://nginxhost/es/* Trying 192.168.5.171:9201...
* Connected to 192.168.5.171 (192.168.5.171) port 9201
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* SSL certificate problem: self signed certificate
* Closing connection
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
* Host localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:80...
* Connected to localhost (::1) port 80
* Server auth using Basic with user 'admin'
> GET /es/ HTTP/1.1
> Host: localhost
> Authorization: Basic YWRtaW46YWRtaW4=
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx/1.27.4
< Date: Thu, 24 Apr 2025 07:45:10 GMT
< Content-Type: application/json; charset=UTF-8
< Content-Length: 552
< Connection: keep-alive
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, POST, OPTIONS
< Access-Control-Allow-Headers: Authorization,Content-Type
<
{"name" : "easysearch-node1","cluster_name" : "infinilabs","cluster_uuid" : "VcMD__DwSYSUqear8wp-XA","version" : {"distribution" : "easysearch","number" : "1.11.1","distributor" : "INFINI Labs","build_hash" : "4d0be0343919fb1a605e3c8284326b7e069eb9bf","build_date" : "2025-03-14T09:33:12.182925Z","build_snapshot" : false,"lucene_version" : "8.11.4","minimum_wire_lucene_version" : "7.7.0","minimum_lucene_index_compatibility_version" : "7.7.0"},"tagline" : "You Know, For Easy Search!"
}
* Connection #0 to host localhost left intact
本次將 Nginx 的訪問認證密碼修改為 admin123
后,發現在請求過程中出現了兩次身份驗證的提示。具體表現為:當用戶輸入錯誤的密碼時,Nginx 會首先返回一次 401 Unauthorized。由于 Nginx 與 EasySearch 使用了不同的認證信息,Nginx 在將請求頭(包括 Authorization 字段)轉發至 EasySearch 時,EasySearch 檢測到憑據不匹配,也會返回一次 401。由此導致了雙重身份認證失敗的現象,影響了正常訪問流程。
curl -v -u "admin:admin" http://localhost/es/* Trying 192.168.5.171:9201...
* Connected to 192.168.5.171 (192.168.5.171) port 9201
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* SSL certificate problem: self signed certificate
* Closing connection
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
* Host localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:80...
* Connected to localhost (::1) port 80
* Server auth using Basic with user 'admin'
> GET /es/ HTTP/1.1
> Host: localhost
> Authorization: Basic YWRtaW46YWRtaW4=
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.27.4
< Date: Thu, 24 Apr 2025 09:21:09 GMT
< Content-Type: text/html
< Content-Length: 179
< Connection: keep-alive
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm="Restricted Area"
<
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.27.4</center>
</body>
</html>
* Connection #0 to host localhost left intact
?xu?~/OrbStack/docker/containers/secure-nginx/etc/nginx??? curl -v https://192.168.5.171:9201/ (base) 17:21:09curl -v -u "admin:admin123" http://localhost/es/* Trying 192.168.5.171:9201...
* Connected to 192.168.5.171 (192.168.5.171) port 9201
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* SSL certificate problem: self signed certificate
* Closing connection
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.htmlcurl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
* Host localhost:80 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:80...
* Connected to localhost (::1) port 80
* Server auth using Basic with user 'admin'
> GET /es/ HTTP/1.1
> Host: localhost
> Authorization: Basic YWRtaW46YWRtaW4xMjM=
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.27.4
< Date: Thu, 24 Apr 2025 09:21:16 GMT
< Content-Type: application/json; charset=UTF-8
< Content-Length: 381
< Connection: keep-alive
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm="Security" charset="UTF-8"
<
* Connection #0 to host localhost left intact
{"error":{"root_cause":[{"type":"security_exception","reason":"Missing authentication information for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"Security\" charset=\"UTF-8\""}}],"type":"security_exception","reason":"Missing authentication information for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"Security\" charset=\"UTF-8\""}},"status":401}?
場景編號 | Nginx 是否開啟認證 | EasySearch 是否開啟認證 | 實際認證次數 | 說明 |
---|---|---|---|---|
① | 否 | 否 | 0 次 | 完全開放,任何請求無需驗證。 |
② | 否 | ? 是 | 1 次 | 訪問時直接彈出 EasySearch 的認證窗口,用戶需輸入憑證。 |
③ | ? 是 | 否 | 1 次 | 僅在 Nginx 層驗證,驗證通過后直接訪問后端。 |
④ | ? 是 | ? 是 | 2 次(默認) | Nginx 和 EasySearch 各自認證,用戶需連續輸入兩次密碼。 |
⑤ | ? 是 | ? 是 | 1 次(透傳,proxy_pass_request_headers on;) | Nginx 開啟認證,并通過 proxy_set_header Authorization 透傳給 EasySearch,用戶僅需輸入一次密碼即可完成認證。 |