網站反向代理老是出包,結果原因竟然是在這…

最近我在入口網站上加了前往開發中網站的連結,同時設置了反向代理,使得這個連結可以直接與位於後方的開發中網站相通;經過了幾天的努力,還有排除了中途出現的一些突發狀況,在今天總算是搞定了。

最近我的網站系統可說是多事之秋,動不動就出狀況。大致列舉如下:

  1. 分享器拿不到對外IP:雖然先前我把現用的TL-WR740N轉刷成DD-WRT,把這個問題暫時解決了。但是最近不知是不是DD-WRT的設定有錯還是軟體問題,這個問題又出現了。後來乾脆一不做二不休,把DD-WRT重置了一遍(不是換回原廠韌體喔!我可不想再繼續跟原廠韌體鬥智鬥勇了),再把相關的設定全數手工回復。現在這個問題大致上是已經解決了。
  2. 網站伺服器一開機就Kernel Panic:這是令我最頭痛的問題。發生之前完全沒有任何徵兆,就在一次我要用SSH連線時發現不正常,以為只要重開機就可以解決;想不到重開機後就變成這個狀況。原以為是記憶體或硬碟有問題,然而對這兩個地方檢查,全都是好的(記憶體用memtest86+跑過一遍,正常;硬碟用Linux Mint的LiveUSB開機檢查,也都正常,所有硬碟槽都能掛載)。最後我能想到的問題點,就是這個系統本身已經壞掉了。這個系統上還有網站、資料庫等東西,而且還是正式運作的網站。網站跟一些程式的設定檔倒是不難備份,只要用幾道指令複製出來(或是用LiveUSB逐個複製出來)並存到安全的地方,就可以了。
    但是有個大問題來了,就是「資料庫的備份」。一般我是習慣用phpmyadmin將整個資料庫匯出成一個檔案,還原時只要將檔案匯入即可,最後將有關權限重新設定就行了。這個方法需要在系統能正常運作的情況下才能用,而如今系統連進去都不行,所以這方法只能掰掰了。後來發現可以將資料庫的相關檔案備份起來,事後再還原回去就好。於是我就採用了這個方法,將整個資料庫備份下來。最後就是將損壞的系統重裝了。
  3. 反向代理設定結果不如預期:這是本篇文中我所要紀錄的了。

開發中網站與主要網站分離

我的構想是:將目前直接對外開放的網站伺服器(以下使用「前端伺服器」稱之)定位為正式運作中的網站伺服器,上面的設定能不動就不動。另外再用一台閒置的主機,作為開發中網站的伺服器(以下使用「後端伺服器」稱之)。我所計畫的配置如下:

  1. 兩個伺服器可以共用一個對外固定IP連線:雖然我目前使用的網路還有3個浮動IP可以用,但是這樣的話就必須額外裝一台hub,才能讓兩台伺服器使用不同的IP連線;而問題是並沒有多的插座來給hub供電了,所以只能設法讓它們倆共用一個固定IP。
  2. 透過前端伺服器「反向代理」至開發中網站的伺服器(以下簡稱後端伺服器)
    原因主要為以下兩點:

    1.  兩台伺服器的對外連接埠都一樣:眾所周知,http的連接埠是80,而這個連接埠與https的連接埠443都被前端伺服器拿去用了(實務上是用後者,前者是為了相容性而保留下來的),後端伺服器只能使用別的連接埠。
    2. 承上一個原因,我不希望訪客在打網址時還需要多加埠號。於是,我就另外在No-IP上設了一組網址(我的帳號最多可設置三組網址,現在已經全都用了),專門給它用。
  3. 代理端設置HTTPS連線,以配合系統的HSTS設置(HSTS會要求瀏覽器使用HTTPS連線)。

實作過程

雖然反向代理一般都是使用Nginx來設置,而且我實際搜尋的時候,找到的教學也是以Nginx的居多;但是我個人只懂Apache,而且我也不想要為了實作反向代理而將Apache換掉改用Nginx(很多地方都要重新設定),於是我就尋找使用Apache實作反向代理的方法。

結果很幸運的,Apache也是可以實作反向代理。然後我就按照上面的內容實際寫了4個VirtualHost設定檔:

  1. 後端伺服器上線時:反向代理連線至該伺服器
  2. 下線時:傳回一個網頁,顯示伺服器已下線
  3. 以上兩個重複,但加入HTTPS相關設定,同時在前兩者設定跳轉

一開始是可以順利反向代理,但此時有個問題:混合的內容。簡單來說就是最終傳回的內容包含已加密和未加密的內容,其症狀就是顯示出來的網頁樣式會「走鐘」。原因很簡單,因為內部的連線(兩台伺服器間)走的是http,而對外是https,兩者並不一致。
當時我為了解決這個狀況遍尋了各處,甚至有放棄的打算(感覺這方法不可行);然而皇天不負苦心人,最終讓我找到了方法,就是在設定檔當中加入這一條設定參數:

RequestHeader set X-Forwarded-Proto “https”

這條參數是要求被代理端(後端伺服器)傳送資料給代理端(前端伺服器)時,將X-Forwrded-Proto的值改成https,解決部份內容未加密的狀況,也就不會有「混合的內容」這一問題。

於是反向代理就順利完成設定了。

另外,因應後方的伺服器並非24小時上線,我便設置了下線時的設定檔,並使用Linux的cron排程自動切換。

反向代理在分享器重置後失效?!

由於前文我提到分享器有時會抓不到對外IP(特別是在修改了DD-WRT的一些設定之後,需要系統重開機時),索性把分享器重設。在重設之後,所有內部與伺服器有關的IP都必須作修改(從先前用的192.168.0.0網段改成192.168.1.0網段)。修改之後除了反向代理外,其他部份基本都恢復正常運作了。

為什麼說除了反向代理外?因為這時候反向代理又出了一個新問題:連線的時候會顯示503訊息。查了一下錯誤紀錄檔,發現是無法連線到伺服器所致。那麼問題來了:我都把所有內部與伺服器有關的IP位址改了啊,怎麼會連不到?

首先檢查的是這幾個防火牆:

  1. 前端伺服器:防火牆正常
  2. 後端伺服器:防火牆沒有開
  3. 分享器的防火牆:有開(重點來了!)

原因就是在於分享器的防火牆中有個叫做「ARP欺騙防護」選項。當我把它關掉的時候,就沒有503錯誤,可以正常顯示出後端伺服器的入口網站;打開的時候,就會跳出503錯誤。

但後來我又發現了一個地方,就是DHCP這裡少開了一個選項:

別問我為什麼不設成中文,因為設成中文的話少許頁面會顯示亂碼 (因為DD-WRT的網頁編碼不是UTF-8)

這個選項就是上圖中的「Use NVRAM for lient lease DB」,意思是將DHCP用戶端清單儲存在分享器的NVRAM上(相當於在分享器上設置一個ARP表,這是我個人的理解);這時候再將防火牆裡的ARP欺騙防護打開之後,就不會再有503錯誤了。
(設定完之後要將分享器重新開機,這些設定才會生效,否則還是一樣會報503錯誤)

對於這個問題,我能想到的可能原因就是:分享器上沒有網路上所有電腦的ARP表(也就是在DDWRT中,Status標籤頁裡的LAN子標籤頁中的”DHCP Clients”);如果這裡空無一物又開啟ARP欺騙防護的話,就會發生無法連線的狀況(簡單來說就是無法找到這個IP位址是對應到哪個主機的MAC位址),最終造成代理端傳回503錯誤。

如果有開啟上述的選項,就等於說分享器擁有了整個網路的ARP表,在ARP欺騙防護開啟時,因為可以找到IP對應的MAC位址,所以就可以正常連線了。我不知道背後原理是不是如此,但至少我實測的結果是這樣。


謹以此文提供給任何有在架站,且對外分享器也使用DD-WRT,且遇到這種問題的朋友作個參考。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料