Skip to content

反向代理(URL 路徑字首)

在反向代理後將 Potato 部署到子路徑下,例如 https://host/app1/。配置部署 URL 字首,使靜態資源、標註操作和即時流在掛載路徑下都能正確解析。

Potato 可以在反向代理後以 URL 子路徑執行,例如 https://host/app1/,當多臺內部伺服器共享同一個公網 HTTPS 端點時,這種方式很常見:

text
https://host/app1/  ->  http://127.0.0.1:8000/
https://host/app2/  ->  http://127.0.0.1:8001/

標註介面通過根相對 URL(/static/.../updateinstance/annotate/media/...)載入靜態資源並執行操作。當 Potato 掛載到 /app1 下時,這些 URL 否則會相對公網根目錄解析,表現為 CSS 和 JS 出現 404、介面隱藏,或自動儲存失敗並提示“annotations not saved”。部署字首無需針對每個站點修改 nginx 即可解決此問題。

工作原理

下面兩種方案都會設定 WSGI 的 SCRIPT_NAME,Potato 將其作為唯一可信來源,用於服務端渲染的 url_for(...) 輸出以及暴露給瀏覽器、作為 window.config.url_prefix 的客戶端字首。該字首會包裹 fetch()sendBeacon()EventSource 以及根相對的 href/action/src 屬性。當未設定字首時,SCRIPT_NAME 為空,不會有任何變化,因此對於普通的 potato start 執行這是一個空操作。

方案 A — POTATO_PROXY_FIX(代理傳送轉發頭)

當你掌控代理且它能夠傳送轉發頭時使用此方案。Potato 會啟用 Werkzeug 的 ProxyFix,它會逐請求讀取 X-Forwarded-Prefix(以及 -Proto/-Host/-For)。

bash
export POTATO_PROXY_FIX=1
potato start config.yaml -p 8000

nginx,剝離字首並將其作為頭轉發:

nginx
location /app1/ {
    proxy_pass         http://127.0.0.1:8000/;   # trailing slash strips /app1/
    proxy_set_header   Host              $host;
    proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_set_header   X-Forwarded-Prefix /app1;
}

ProxyFix 信任轉發頭。僅當應用只能通過受信任的代理訪問時才啟用 POTATO_PROXY_FIX。如果內部埠也可被直接訪問,客戶端便可能偽造 X-Forwarded-Prefix-Host,從而汙染生成的 URL。

方案 B — POTATO_URL_PREFIX(代理配置無法更改)

當你無法新增轉發頭但已知公網掛載路徑時使用此方案。Potato 會自行將字首注入 SCRIPT_NAME

bash
export POTATO_URL_PREFIX=/app1
potato start config.yaml -p 8000

代理仍必須在轉發前剝離字首,以便 Flask 收到無字首的路徑,例如 /static/styles.css

nginx
location /app1/ {
    proxy_pass       http://127.0.0.1:8000/;     # trailing slash strips /app1/
    proxy_set_header Host $host;
}

如果兩個變數都已設定,逐請求轉發的字首優先,POTATO_URL_PREFIX 作為後備。

即時流(伺服器傳送事件)

即時代理和即時編碼檢視器使用 SSE。URL 字首會自動應用,但 SSE 還需要代理在流位置上停用緩衝,否則事件會被滯留:

nginx
location /app1/api/ {
    proxy_pass            http://127.0.0.1:8000/api/;
    proxy_set_header      Host $host;
    proxy_buffering       off;
    proxy_read_timeout    3600s;
}

驗證

  1. 載入 https://host/app1/,確認 CSS 和 JS 載入且沒有 404。
  2. 進行一次標註,確認其自動儲存。
  3. 導航“下一個/上一個”,確認媒體和資料正常渲染。
  4. 如果使用即時代理評估,確認流連線並更新。

注意事項與限制

  • 顯示的標註內容內部的根相對連結也會被加上字首。打算指向公網根目錄的內容作者應使用絕對 URL。
  • 通過 pip 安裝的部署依賴打包的靜態資源;請確保你的構建包含巢狀的 static/ 目錄。
  • Potato 2.9 把字首擴充套件到靜態檔案、客戶端 fetch 和媒體 URL,以及每個獨立頁面:管理後臺、儀表板、會話審閱和舊版 v1 頁面(#168,作者 Aldo Costa)。
  • 在 Potato 2.9 之前,登入表單、/done/logout/pocket、密碼重置表單和管理後臺的重定向都會忽略字首,媒體的 postersrcsettrack URL 也沒有加字首。如果經過代理的部署在其中任何一處丟失了字首,請升級。

相關內容

有關實現細節,請參閱源文件