將 Apache 的 .htaccess 轉換成 Nginx 設定檔屬於「先期翻譯」的問題,而不是單純的複製貼上。Apache 每次請求都會沿著目錄結構讀取 .htaccess,而 Nginx 則是讀取一份集中式設定檔,並透過 server 與 location 區塊來套用。若轉換工具在沒有提示的情況下改寫整份 .htaccess,可能會產生語法正確但語意錯誤的指令,一條行為不當的重新導向甚至可能讓公開網站離線。htaccess to Nginx Converter 只處理一小部分有完整文件的指令,其餘部分則以行號回報,讓人工接手完成。輸出結果是一段可供審閱的片段,而不是完整的 nginx.conf,你仍須自行決定每行程式碼該放在哪裡、備份現行設定檔,並在重新載入前執行 nginx -t。本文將逐步說明這個工具實際會翻譯哪些內容、如何安全地使用,以及在把正式流量指向結果之前應該進行哪些檢查。

convert apache htaccess to nginx
convert apache htaccess to nginx

htaccess to Nginx Converter 實際上會翻譯哪些內容

這個工具採取刻意縮小的契約。它一次只接受一段聚焦於 document-root 的 .htaccess 摘錄,並以單一有界限的行為單位逐行處理,會忽略 RewriteEngine On、保留註解,並且只輸出它能負責的指令。支援的 rewrite 形式是一行 RewriteRule,其中包含一個樣式、一個替代字串,以及一組以方括號包裹的旗標;自動處理的旗標集合刻意僅限於 L、R、R=301 與 R=302。Apache 的永久重新導向會對應到 Nginx 的 permanent 旗標,暫時重新導向會對應到 redirect,而內部的 last 規則會對應到 last。在 document-root 的 .htaccess 中,樣式通常是在移除目錄前置詞後對路徑進行比對,因此常以插入號開頭而沒有斜線;Nginx 的 rewrite 樣式所看到的 URI 開頭會帶有斜線,因此轉換器會為支援的根目錄情境樣式補上那個前置斜線。

另外也支援三個非 rewrite 的對應。Options -Indexes 會轉成 autoindex off;,本地的 ErrorDocument 404 路徑會轉成 error_page 404 並沿用相同路徑,而帶引號的 X-Robots-Tag Header set 值會轉成一行 add_header。整個處理流程都在瀏覽器中完成,輸入內容不會送到 Lizely,如此可避免含有憑證或僅限測試環境的設定片段外洩。其他狀態碼、外部的錯誤文件、條件式標頭、環境變數與指令容器,則需要手動遷移。

如何安全地將 htaccess 轉換成 Nginx

  1. 將一段聚焦於 document-root 的 .htaccess 摘錄貼進轉換器。保持輸入內容簡短,範圍限定在單一虛擬主機或 document root。這個工具只會翻譯明確支援的指令子集,若貼上整份檔案,會讓警告更難以分門別類處理。
  2. 逐行檢視輸出內容,並手動處理每一個帶行號的警告。在移植之前,請將每一條被標記的規則與 Apache mod_rewrite 介紹 以及 Nginx 的 rewrite 模組參考文件交叉比對,確認其預期行為。警告屬於結果的一部分,而不是 bug。
  3. 將轉換後的片段合併到正確的 Nginx 區塊中。判斷每行程式碼應該放在 server 區塊還是特定的 location 區塊,然後放到對應位置。這段片段本身不會建立 http、server 或 location 區塊,也不會幫你選擇 listen 埠、設定 server_name、設定 TLS、定位 document root、保留 PHP 路由、轉發 proxy 或定義日誌。
  4. 在動到現行設定之前先備份。保留一個可隨時回復的工作階段,將正在編輯的檔案納入版本控制,並在可行的情況下於非正式環境的主機上先行測試。
  5. 執行 nginx -t,並在測試環境中驗證具代表性的請求。請確認回應的 Location 標頭,而不是只看瀏覽器的網址列。只有在語法檢查與請求測試都通過之後,才重新載入 Nginx。

哪些會被轉換,哪些只會被標記

下表整理了支援的對應關係,以及會產生警告而非輸出的情況。任何屬於條件式、不熟悉或語意模糊的內容,都會以原始行號回報以便手動處理,這也說明了為什麼一段簡短、附帶行號的警告,會優於憑猜測做出的 rewrite。

Apache 來源 Nginx 輸出 原因
RewriteRule ^old$ /new/ [R=301,L] rewrite ^/old$ /new/ permanent; 支援:帶 last 的永久重新導向,會補上前置斜線
RewriteRule ^page$ /index.php [L] rewrite ^/page$ /index.php last; 支援:內部 last 規則
RewriteRule ^/api/(.*)$ /$1 [L] rewrite ^/api/(.*)$ /$1 last; 支援:保留前置斜線的樣式
Options -Indexes autoindex off; 支援:停用目錄列表
ErrorDocument 404 /404.html error_page 404 /404.html; 支援:透過 nginx core error_page 設定本地 404 文件
Header set X-Robots-Tag "noindex" add_header X-Robots-Tag "noindex"; 支援:帶引號的 X-Robots-Tag 標頭
RewriteCond %{HTTPS} off 後接一條規則 僅警告,不輸出規則 條件式永遠不會被自動翻譯
RewriteRule ^page$ /new/ [QSA,L] 僅警告,不輸出規則 不明的旗標 QSA 會中斷規則轉換
RewriteRule ^page$ - [F,L] 僅警告,不輸出規則 以破折號為目標時不予輸出,以避免產生不安全的轉換結果

RewriteCond 這類行永遠不會被自動翻譯,因為其中的變數、擷取內容、評估順序與部署情境都可能改變其語意。當 RewriteRule 前面帶有條件式時,工具會連同該規則一起抑制,而不是輸出一條可能改變流量、造成迴圈或暴露路由的非條件式重新導向。像 QSA、END、F、G、B 或 NC 這類不明旗標,會停止該規則的轉換,因為其細節無法在確保安全的情況下被消弭。Apache 中以單一破折號表示「無替代字串」的目標同樣會被略過,因為它常搭配會改變存取或處理方式、卻不更動 URI 的旗標,而一個字面的破折號在 Nginx 中並不是安全的對應。

在重新載入前值得特別標記的遷移陷阱

Apache 與 Nginx 使用不同的請求處理模型。Apache 的 .htaccess 是透過目錄被找到,並且可以被 AllowOverride 停用;Nginx 則讀取集中式設定,並在進行 rewrite 處理之前先選定 server 與 location 區塊。即使是完全相同的正規表達式,行為也可能不同,因為被比對的字串、跳脫方式、查詢字串處理與迴圈行為都不一樣。對於每一條非單純的規則,請同時閱讀兩份官方手冊,並把任何涉及身分驗證、授權、防盜連、proxy 邏輯、CMS front-controller 規則或複雜條件式的內容視為工程工作,而不是單純的文字批次替換。若想以敘事方式了解同一套流程套用到真實摘錄上的做法,可參考姊妹指南 Convert Apache .htaccess to Nginx Rules Without Guesswork

永久重新導向需要格外小心,因為瀏覽器與中間節點可能會將其快取。在可行的情況下,請先在受控環境中使用暫時重新導向,並在測試過舊路徑、新路徑、查詢字串、其他主機與 HTTPS 行為後,才改為永久重新導向。請確認回應的 Location 標頭,而不是只依賴瀏覽器的網址列。一行程式碼可能在語法上正確,卻與其所屬的上下文不相符;一個會悄悄寫出看似合理、實際上不等價設定的轉換器,比一個留下明確待辦事項的轉換器更為危險。

安全上線前的重新載入前檢查清單

  • 備份目前的 nginx.conf 以及所有被引入的檔案,並確認能從你的 shell 將備份還原。
  • 確認轉換器所產生的每一個警告都已處理完畢或已被明確延後,並將每一處手動修改記錄下來。
  • 對組裝完成的檔案執行 nginx -t。測試通過是必要條件,但並非充分條件。
  • 在測試環境中驗證具代表性的請求,包含舊路徑、新路徑、查詢字串、其他主機與 HTTPS 行為。
  • 使用 curl -I 或標頭檢查工具確認重新導向的回應 Location 標頭,而不是只靠瀏覽器的網址列。
  • 在可回復的維護時段內進行上線,並準備好可在首次重新載入出現問題時立即還原設定的工作階段。
  • 保留一份原始的 .htaccess 以便比對,並將新的 Nginx 設定納入版本控制。

把這個轉換器當作盤點助理:貼上一段聚焦的摘錄、檢視轉換後的行數、處理每一個警告、將結果組裝到一份納入版本控制的 Nginx 檔案中,並在重新載入前於測試環境完成驗證。如果你的來源內容包含身分驗證、授權、防盜連、proxy 邏輯、CMS front-controller 規則或複雜條件式,請將此次遷移視為工程工作,而不是單純的文字批次替換。

若你正在權衡各種做法,How to Create a .htaccess File in Apache Server 對此有詳細說明。