將 Apache .htaccess 檔案遷移至 Nginx 是個帶有嚴格限制的轉譯問題,而初學者友善的做法首先要接受一點:Apache 的每目錄指令與 Nginx 的集中式設定區塊並不能互換。Apache 會在每次請求時評估 .htaccess,沿著目錄樹向下走,並套用範圍限定於各資料夾的規則;Nginx 則只會讀取一次階層式設定,然後在任何 rewrite 執行前選擇一個 server 與 location 上下文。正因為這個差異,「直接轉換」並不存在作為一個安全的操作。將這兩種格式視為等價的初學者,最後往往會遇到 rewrite 迴圈、指向錯誤主機的被快取重新導向,或是永遠不會觸發的本機 404 頁面。一個範圍明確的轉換工具對第一輪有幫助:它會轉譯一小組精選的指令,並以行號回報其他所有內容,讓你可以參考官方 Apache 與 Nginx 文件,手動完成剩下的遷移工作。

htaccess to nginx for beginners
初學者將 htaccess 轉換至 Nginx:安全的第一步遷移

Apache .htaccess 與 Nginx 之間的架構落差

Apache 的 .htaccess 是個每目錄覆寫層。每個請求會走訪路徑,而伺服器會合併沿途找到的任何啟用 AllowOverride 的指令。RewriteCond、RewriteRule、ErrorDocument、Header、Options 與驗證區塊都可以存在於單一資料夾中,而且修改它們只需要編輯檔案並等待下一個請求。Nginx 沒有對應的迴圈。它在啟動時只讀取設定一次,為進來的連線挑選一個 server 區塊,然後為 URI 選擇一個 location 區塊。Nginx 核心 error_page 指令以及它的 rewrite 同類指令就住在這些區塊裡;它們不會透過走訪檔案系統而被重新發現。

由此衍生出三個實際的後果。第一,Nginx 的 rewrite 模式看到的是以斜線開頭的 URI,而 document-root 的 .htaccess RewriteRule 通常會去掉那個前綴。第二,Apache 的 RewriteCond 可以檢查伺服器變數,而 Nginx 對這些變數的評估方式不同,甚至完全不評估。第三,Apache 對每個請求套用的條件式標頭與存取控制指令,沒有可移植到 Nginx 的對應表示式。初學者用的轉換工具只能轉譯刻意縮小的指令子集,因為其餘的表面範圍必須手動遷移。

初學者用的轉換工具應該做與不應該做的事

初學者用的轉換工具靠做兩件事來證明價值:把少數能乾淨轉譯成 Nginx 行的規則轉換出來,以及指出其餘所有項目。它應該拒絕猜測。一個會產出看起來合理的 RewriteCond 轉譯、悄悄丟掉不支援的旗標,或是圍繞你的片段虛構出一個 server 區塊的工具,最終會讓網站離線。特別是初學者,在信任任何轉換工具之前,應該留意以下行為:

  • 一份可稽核的支援指令清單,而不是「完整覆蓋」的行銷承諾。
  • 保留原始 .htaccess 上下文、附帶行號的警告。
  • 刻意縮小的旗標集合,例如 L、R、R=301 與 R=302,其餘一律拒絕。
  • 在瀏覽器中本地處理,不上傳輸入內容。
  • 輸出明確只是一個片段,而不是完整的 nginx.conf。

這份契約符合 htaccess to Nginx Converter 的做法:它會忽略 RewriteEngine On、保留註解、對任何條件式或不熟悉的內容回傳警告,並且從不宣稱自己能獨力完成遷移。

htaccess to Nginx Converter 對首次使用者的運作方式

  1. 開啟工具,貼上 document-root .htaccess 中一段聚焦的摘錄,而不是整個檔案。僅保留你希望這輪檢視的 RewriteRule、Options、ErrorDocument 與 Header 設定行。
  2. 僅轉換支援的指令子集。工具會為符合其嚴格契約的規則產出 Nginx 行,忽略 RewriteEngine On,並保留你的註解。
  3. 在將任何內容複製到你的設定檔之前,逐行檢視每一行產出,並依據 Apache mod_rewrite 介紹 與 Nginx 文件手動處理每一個帶行號的警告。
  4. 將檢視過的行合併到正確的 Nginx 上下文中 —— 通常伺服器層級的重新導向與標頭使用 server 區塊,而路徑範圍的 rewrite 使用 location 區塊 —— 並先備份當前使用中的設定。
  5. 執行 nginx -t 驗證組裝完成的檔案,接著在預備環境或維護頁後方測試具代表性的請求,然後再發出可能影響線上流量的 reload。

這個迴圈故意設計得很短。轉換、檢視、合併。任何打斷這個迴圈的事 —— 一個你無法處理的警告、一個你不認得的旗標、一個涉及 HTTPS 或主機狀態的條件 —— 就是停下來閱讀手冊而不是猜測的時機。

轉譯支援的指令:逐步示範

Apache 指令 轉換工具的動作 Nginx 結果
RewriteRule pattern target [L] 為 document-root 模式插入前置斜線,保留反向引用 rewrite ^pattern(/.*)$ /target$1 last;
RewriteRule pattern target [R=301] 將 Apache 永久重新導向視為 nginx 的 permanent 旗標 rewrite ^pattern$ /target permanent;
RewriteRule pattern target [R] 將暫時重新導向視為 nginx 的 redirect 旗標 rewrite ^pattern$ /target redirect;
RewriteRule pattern target [QSA, END, F, G, B, NC] 為該規則標記旗標未轉換,並產生警告 (不產出任何行)
RewriteCond ... 抑制其後的規則;條件式不予轉譯 (不產出任何行)
RewriteRule pattern - [flags] 保留不替換的 dash 目標不處理 (不產出任何行)
Options -Indexes 直接對應 autoindex off;
ErrorDocument 404 /local-404.html 對應本機 404 路徑 error_page 404 /local-404.html;
Header set X-Robots-Tag "value" 對應帶引號的值 add_header X-Robots-Tag "value";

有三個細節值得留意。第一,支援的 rewrite 形式必須包含以方括號括起的旗標清單;沒有旗標的規則會被回報為模稜兩可。第二,前置斜線的插入是一個有書面記載的範圍假設:它預設摘錄來自 document-root 的 .htaccess,而不是來自帶有 Alias 對映的巢狀資料夾。第三,X-Robots-Tag 的對映只有在值是帶引號字串時才會生效;條件式標頭與環境變數仍須手動處理。

閱讀警告而非忽略警告

警告清單是轉換工具最重要的輸出,因為它會告訴你工具拒絕做了哪些事。初學者應該把每一個警告視為待辦項目,而不是雜訊。支援的旗標集合刻意限制為 L、R、R=301 與 R=302。諸如 QSA、END、F、G、B 或 NC 等未知旗標會停止該規則的轉換,因為它們的語意無法安全抹除 —— QSA 會附加查詢字串、F 會回傳 403,而 NC 以改變比對表面範圍的方式控制大小寫敏感度。

RewriteCond 設定行永遠不會自動轉譯。Apache 的條件可以檢查 HTTPS 狀態、主機名稱、檔案、目錄、查詢字串、標頭與擷取群組,而其評估順序很重要。當 RewriteRule 接在某個條件之後時,工具會抑制該規則,而不是輸出一條可能改變流量、產生迴圈或暴露路由的非條件式重新導向。以單一 dash 寫成的 Apache 不替換目標同樣會被保留不處理:它經常與會改變存取或處理方式但不變動 URI 的旗標搭配,而字面上的 dash 在 Nginx 中並非安全的替代。

一般的規則很簡單:指令越冷門,你越應該把 Apache 與 Nginx 的文件並排閱讀。即使長相相同的正規表示式,行為仍可能不同,因為兩種伺服器之間,被比對的字串、跳脫方式、查詢處理與迴圈行為並不一致。

在重新載入 Nginx 之前的安全合併檢查清單

轉換工具回傳的是片段,不是完整的設定。它不會建立 http、server 或 location 區塊,不會選擇 listen port,不會設定 server_name,不會設定 TLS,不會定位 document root,不會保留 PHP routing,不會轉發 proxy,也不會定義 log。把檢視過的行放到錯誤的上下文中,是初學者遷移最常出錯的原因。一行設定可能在語法上有效,但對其所處的上下文來說是錯的,這就是為什麼在任何 reload 之前,手動的檢查清單很重要:

  • 備份當前使用中的設定,並保留一個開啟中的復原工作階段。
  • 將 rewrite 規則放在與原始 Apache 資料夾範圍相符的 server 或 location 區塊內。
  • 使用 nginx -t 驗證組裝完成的檔案;通過語法檢查是必要條件,但並不足夠。
  • 在預備環境測試具代表性的請求,包括舊路徑、新路徑、查詢字串、替代主機與 HTTPS 行為。
  • 在受控環境中盡可能先從暫時重新導向開始,確認 Location 標頭無誤後,再切換為永久重新導向。
  • 只要來源包含驗證、授權、防盜連、proxy 邏輯、CMS front-controller 規則或複雜條件,就把這次遷移視為工程工作來處理。

永久重新導向需要格外小心,因為瀏覽器與中介層可能會快取它們。請確認回應的 Location 標頭,而不是只依賴瀏覽器網址列。一次失敗的 reload 或重新導向迴圈可能讓公開網站離線,而把舊 URL 指向錯誤主機的快取,比原始的 bug 更難復原。如果來源包含超出支援子集以外的任何內容,請把這次遷移視為工程工作,而不是批次文字替換。

延伸閱讀:WordPress 預設 robots.txt:安全的起點。

延伸閱讀:初學者 SERP 摘要預覽:第一次操作指南。