Lizely 轉換工具的 htaccess to nginx 對照表,涵蓋的是一個刻意限縮的子集:只使用 L、R、R=301,與 R=302 旗標的 RewriteRule 行、Options -Indexes、本機的 ErrorDocument 404 路徑,以及一個帶引號的 X-Robots-Tag Header set 數值。其他所有內容——RewriteCond 區塊、像 QSA、END、F、G、B,或 NC 這類不熟悉的旗標、不做替換的破折號、環境變數、代理邏輯,以及條件式標頭——都會連同原始行號一起回報,留給人工處理,而不是被悄悄用猜的。輸出結果,是一份經過審查的片段,而不是一份完整的 nginx.conf,因此每一行,都必須放進正確的 server 或 location 情境中,用 nginx -t 驗證過,並在具代表性的請求上測試過,才能重新載入。來自文件根目錄 .htaccess 的樣式,通常比對的是已經去除目錄前綴的路徑,因此這個轉換工具,會插入 Nginx 重寫樣式所預期的開頭斜線。Apache 與 Nginx,透過不同的架構處理請求,這也是為什麼一份附帶明確警告、可供稽核的對應表,會比一次悄悄進行、可能在沒有人注意到的情況下改變流量走向的最佳猜測式翻譯,來得更安全。

這個轉換工具能辨識什麼(以及它拒絕用猜的內容)
這個htaccess to nginx converter 的運作方式,是一個範圍受限的盤點工具,而不是一個萬用翻譯器。它接受一段聚焦的摘錄——通常是文件根目錄的 .htaccess,而不是巢狀的——並且只輸出上面列出的四種指令形式。任何帶有條件、語法上有歧義,或不在支援旗標集合內的內容,都會以帶行號的警告形式回傳,而不是被猜出來的一行。這項決定,正是這份規範的一部分:一個會悄悄寫出看似合理、實際上並不等價的設定的轉換工具,比一個明確留下工作待辦的工具更危險,因為一行能編譯通過的設定,仍然可能把真實流量,送到錯誤的地方。
有三個類別,被明確排除在範圍之外,永遠都會產生警告:
- RewriteCond 行。 Apache 的條件式,可以檢查 HTTPS 狀態、主機名稱、檔案、目錄、查詢字串、標頭,以及擷取到的群組。它們的求值順序,以及伺服器架構本身,都很重要。當一個 RewriteRule 跟在一個條件式之後,這個工具,也會一併抑制那條規則,而不是輸出一個無條件的重新導向,因為那可能會改變流量、造成迴圈,或暴露出一條路由。
- 不在 {L, R, R=301, R=302} 範圍內的 RewriteRule 旗標。 像 QSA、END、F、G、B,或 NC 這類未知旗標,會讓那條規則的轉換停止,因為它們的細節,無法被安全地抹除。
- 不做替換的破折號目標。 Apache 用一個字面上的破折號,來表示「不要重寫這個 URI」,通常會搭配會改變存取或處理方式、但不改變網址本身的旗標一起使用。一個字面上的破折號,並不是一個安全的 Nginx 替代寫法,因此這個警告,就是結果的一部分。
ErrorDocument 的其他狀態碼、外部錯誤網址、環境變數、像 <IfModule> 這樣的指令容器,以及任何與驗證相關的指令,同樣都不在範圍之內,需要人工遷移。
對照表:Apache 的行,與它們對應的 Nginx 寫法
下表整理了支援的子集,直接取自這個轉換工具已文件化的對應規範,而不是取自第三方的移植版本。任何不在這張表裡的內容,都是刻意留給人工處理的,會以警告的形式呈現。
| Apache 指令 | 輸入範例 | Nginx 輸出 | 備註 |
|---|---|---|---|
| 帶有 [L] 的 RewriteRule | RewriteRule ^old$ /new [L] | rewrite ^/old$ /new last; | 內部的 last 規則,不會產生客戶端往返。 |
| 帶有 [R=301] 的 RewriteRule | RewriteRule ^old$ /new [R=301,L] | rewrite ^/old$ /new permanent; | 永久重新導向;瀏覽器與 CDN 可能會積極快取。 |
| 帶有 [R=302] 的 RewriteRule | RewriteRule ^old$ /new [R=302,L] | rewrite ^/old$ /new redirect; | 暫時重新導向;對分階段上線來說較安全。 |
| 帶有單獨 [R] 的 RewriteRule | RewriteRule ^old$ /new [R,L] | rewrite ^/old$ /new redirect; | Apache 預設把單獨的 R,視為 302;這個轉換工具,遵循同樣的慣例。 |
| 帶有擷取群組的 RewriteRule | RewriteRule ^blog/(.*)$ /news/$1 [L,R=301] | rewrite ^/blog/(.*)$ /news/$1 permanent; | 擷取到的反向參照,會以 $1、$2 等形式保留下來。 |
| Options -Indexes | Options -Indexes | autoindex off; | 為周邊的情境,停用目錄清單顯示功能。 |
| ErrorDocument 404(本機路徑) | ErrorDocument 404 /404.html | error_page 404 /404.html; | 只有帶本機路徑的 404 狀態,會被對應;外部網址與其他狀態碼,需要人工處理。 |
| Header set X-Robots-Tag | Header set X-Robots-Tag "noindex" | add_header X-Robots-Tag "noindex"; | 只有帶引號的靜態數值,會被對應;條件式標頭,以及 unset/環境變數形式的數值,仍需人工處理。 |
| 帶有 [QSA]、[END]、[F]、[G]、[B]、[NC] 的 RewriteRule | RewriteRule ^x$ y [QSA,L] | 在原始行號處產生警告 | 未知旗標;不會輸出任何行。 |
| RewriteCond(任何一種) | RewriteCond %{HTTPS} off | 在原始行號處產生警告 | 條件式永遠不會被翻譯;緊接其後的規則,也會一併被抑制。 |
| RewriteRule 中的 -(破折號目標) | RewriteRule .* - [L] | 在原始行號處產生警告 | 不做替換的目標,會被保留不譯;常與改變存取權限的旗標搭配使用。 |
如何執行轉換,並解決這些警告
每次都用這套流程。它能維持這個工具受限的範圍,並避免一次乾淨的語法檢查,掩蓋掉一個情境上的錯誤。
- 從文件根目錄的 .htaccess 中,複製一段聚焦的摘錄。驗證、授權、防盜連結保護、代理邏輯,以及 CMS 前端控制器規則,都不屬於這個工具的範圍——請把那類遷移,當成獨立的工程工作來處理。
- 把這段摘錄,貼進 htaccess to nginx converter 的表單中。處理過程在瀏覽器中進行;輸入內容,不會被送到 Lizely。
- 對照Apache mod_rewrite introduction 與 Nginx rewrite 模組的文件,逐一檢查每一行輸出的 Nginx 設定。輸出結果,是一個片段,而不是一份完整的設定檔。
- 手動解決每一則帶行號的警告。一則警告,就是一項待辦清單項目:它會確切告訴你,哪一行 Apache 設定沒有被轉換,以及原因。
- 把審查過的這些行,合併到適當的 Nginx 情境中——通常是用於重新導向與錯誤頁面的 server 區塊,或是用於限定路徑重寫的 location 區塊——放進一份受版本控制管理的檔案裡。
- 備份目前生效的設定、保留一個開著的復原連線工作階段,並在重新載入之前,針對組裝完成的完整設定,執行 nginx -t。
- 在一個可回復的維護時段內,用具代表性的請求進行分階段測試:舊路徑、新路徑、查詢字串、替代主機名稱,以及 HTTPS 行為。
- 對於永久重新導向,請先在一個受控環境中,以暫時重新導向的形式開始,只有在確認過回應的 Location 標頭(而不是只看瀏覽器網址列)之後,才切換成永久重新導向,並接受瀏覽器與中介系統,可能會積極快取永久重新導向這個事實。
為什麼這份對應表只涵蓋四種指令
這四種被支援的對應——rewrite、autoindex、error_page、add_header——涵蓋的是能在 Apache 逐目錄的設定模型,與 Nginx 集中式、依情境選取的設定模型之間,乾淨轉換的那些情況。要再往前走,就意味著要做出這個工具,光靠貼上的摘錄,無法自行驗證的架構性假設。
舉例來說,RewriteCond %{HTTPS} off 後面接著一條重新導向規則,看起來應該要變成一個 if ($scheme = http) 區塊,但同一條規則,如果出現在一個巢狀的 .htaccess、一個 Alias 對應,或一個已經用不同方式處理 HTTPS 的 location 中,行為就會不一樣。根據 Apache mod_rewrite introduction,條件變數、擷取群組,以及求值順序,會依規則所在的位置不同,而改變意義。這個轉換工具,會回報這一行,然後停下來。
同樣保守的態度,也適用於開頭斜線的插入。一個文件根目錄的 .htaccess 樣式,通常以插入符號開頭,但不帶斜線,因為 Apache,會在比對之前,先去除目錄前綴。而 Nginx 的重寫樣式,看到的則是一個以斜線開頭的 URI。這個工具,會為支援的根情境樣式,插入這個斜線,並把它稱為一項有文件記載的範圍假設,而不是適用於巢狀 .htaccess 檔案、Alias 對應,或特定 location 的 Nginx 區塊的通用轉換規則。
在對照表之後:擺放位置、驗證,與重新載入
一行設定,可能在語法上有效,卻在情境上是錯的。這個片段,不會建立一個 http、server,或 location 區塊,不會選擇監聽埠、設定 server_name、設定 TLS、定位文件根目錄、保留 PHP 路由、轉發代理,也不會定義日誌。擺放位置,是操作者的責任,不是這個轉換工具的責任。
對於一行 autoindex off;,慣例上該放的位置,是在控制你想要保護的那個目錄的 server 或 location 區塊內部。對於 error_page 404 /404.html;,同樣的道理也適用,而且這個路徑,必須能對照到文件根目錄,或情境範圍內的一個 root 指令——Nginx core error_page documentation 是狀態碼與 URI 形式的權威參考來源。對於 add_header X-Robots-Tag "noindex";,範圍很重要,因為 add_header,只有在回應狀態允許插入標頭時才會輸出,因此請測試實際的回應內容,而不是只看重寫後的文字。
在重新載入之前,請用 nginx -t,驗證組裝完成的完整設定、確認 include 的順序,並分階段部署這項變更。一次失敗的重新載入,或一個重新導向迴圈,可能會讓一個公開網站無法存取,而永久重新導向,格外需要小心,因為瀏覽器與中介系統,可能會快取它們。如果你正在把一個負載中的站點從 Apache 遷移出來,你原本 .htaccess 中的設定,可能還包含這個轉換工具完全不會處理的授權、環境變數,或前端控制器邏輯——請把那部分工作,放進一份獨立的計畫中,並針對目標情境,逐項對照官方的 Nginx 指令文件進行驗證。想了解零停機上線的具體做法,Nginx reload without downtime 這篇指南,說明了在組裝完成的檔案通過 nginx -t 之後的操作順序。
想進一步了解,請參閱Nginx Config Generator Alternative for Static Sites。