標籤: nginx

  • 使用 Nginx 基本認證保護動態內容。以一個舊網站為例。

    使用 Nginx 基本認證保護動態內容。以一個舊網站為例。

    最近處理一個舊網站,因為是 demo 用途所以帳號密碼基本上都隨便設定。但是我不想給陌生人掃進來 try error ,所以想到在 Nginx 上上添加 auth_basic 的功能。

    環境如下:

    1. 這個舊網站非常舊,是 ThinkPHP 的 5.x.x 版本
    2. 裡面會 php 設定網址後綴 .html 所以網址會變成 https://xxx.xxx/PATH/ooooo.html 這樣

    先上注意事項:

    1. 我最後選擇保護 .php 檔案,如果有其他需要保護的,甚至靜態檔案請確保 location 的設定。
    2. 因為是 location 選擇 php 檔案,所以驗證通過以後要走一樣的操作順序。
      • 得自首一下,這部分我 try error 很久,是試出來的結論。書到用時方恨少,以後有機會記得補上有系統的原理原則。
    3. 建議使用 HTTPS 避免 header 的帳密被中間人攻擊。
    4. auth_basic 幾個基本知識網路上滿多的,參考這裡這裡這裡

    補上程式碼:

    /PATH_AUTH_BASIC/auth_basic.conf

    # Directory protection rules
    location ~* \.php$ {
        auth_basic "Authorization";
        auth_basic_user_file /PATH/Need_Password.pass;
        # 如果驗證通過則走 PHP 動作
        include PHP-73.conf;
        # 如果是靜態的 .html 文件,則直接嘗試提供
        rewrite  ^(.*)$  /index.php?s=$1  last;   break;
    }
    

    而操作順序, 在 server 的 block 裡面如下:

    ...
    #Directory protection rules
    include /PATH_AUTH_BASIC/auth_basic.conf;
        
    #PHP reference configuration
    include PHP-73.conf;
    
    #REWRITE-START URL rewrite rule reference, any modification will invalidate the rewrite rules set by the panel
    include /PATH_REWRITE/rewrite.conf;
    ...

    補上 ThinkPHP 的 rewrite.conf 主要的設定:

    ...
    location / {
    	if (!-e $request_filename){
    		rewrite  ^(.*)$  /index.php?s=$1  last;   break;
    	}
    	try_files $uri $uri/ =404;
    }
    ...
  • Nginx 中同一個網域設定不同應用程式/目錄

    Nginx 中同一個網域設定不同應用程式/目錄

    技能點還沒有點太多的領域一點點成果就會獲得大大的成就感。

    最近弄了一個可以在同一個網域中實作多的應用程式的設定,這邊紀錄一下。先講結論:

    1. 可以實現同一個網域前後端分離,讓版本控制的操作也分開來。
    2. 同理多個不同應用如果需要互相呼叫時,也可以使用 sub-path 不要 sub-domain 來處理。
    3. 強烈建議不要用套裝的應用程式,關於網域使用的設計需要特別處理。
    4. 個人認為,如果是不同功能的應用場景,還是應該用 sub-domain 處理,這應該是 UX 相關的設計,和技術較為無關。
    5. 系統層的設定較為複雜,包含 Nginx 的設定,如果沒有 full controll 的權限可能實現上較為困難。

    前提列一下:

    1. 主網域是 a.com.tw
    2. 第二個網域是 b.com.tw 作為 nginx 的 proxy 使用,如果有需要也會在 dns 上設定。

    目標有幾個:

    1. 用戶訪問 a.com.tw 時候,會跳轉至 /root-document/a.com.tw/ 路徑上的 web-app
    2. 用戶訪問 a.com.tw/admin 時候,會跳轉至 /root-document/b.com.tw/ 路徑上的 web-app
    3. 用戶訪問 a.com.tw/uploads 時候,會跳轉至 /root-document/b.com.tw/uploads 路徑上的靜態檔案

    實作步驟:

    設定 /etc/hosts 檔案,新增:

    127.0.0.1 b.com.tw

    如果有需要,可以在 DNS 上設定 CNAME 把 b.com.tw 設定為 a.com.tw 別名。

    設定 a.com.tw 的網站,Nginx 中添加:

    # 將 /admin/ 和 /admin/* 路徑指向後端應用程式
    location ^~ /admin/ {
      proxy_pass http://b.com.tw;
    }
    # 將 /uploads/ 和 /uploads/* 路徑的靜態檔案指向其他資料夾
    location ^~ /uploads/ {
      alias /root-document/b.com.tw/uploads/;
      try_files $uri $uri/ /index.html;
    }
    
    
    # Option 其他網站的配置,例如前端 
    location ^~ / {
      root /root-document/a.com.tw;
      ...
    }

    設定 b.com.tw 的網站,Nginx 按照一般的設定即可,不過在動態程式中需要特別注意幾項:

    1. b.com.tw 的顯示網域是主網域 a.com.tw,在畫面上如果顯示非相對域名,要注意顯示的是 a.com.tw 而不是 b.com.tw
    2. 尤其後端上傳行為與 form action 會需要特別注意。
    3. http://b.com.tw 作為後端服務 proxy_pass,要注意 ssl 設定,包含顯示網域的 ssl 是否寫死?或是 proxy_set_header 判斷處理。
    4. uploads 的路徑在範例中也是導向 /root-document/b.com.tw/ 裡面的路徑,如果單純只是靜態檔案也可以自行設定。建議事先規劃整理好。
    5. 需要請注意根目錄設定 .user.ini 檔案中的設定,建議把不同路徑都補進去。

    還有一些小細節:

    1. Nginx 中 alias 的路徑需要是 / 結尾。 alias 和 root 不同的地方,參考這裡
    2. Nginx 路徑匹配優先權問題,請參考這裡

    關於 Nginx 設定的注意事項,附上問 ChatGPT 生成回覆:

    配置意圖

    1. /admin//admin/* 路徑指向後端應用程式
      • location ^~ /admin/ { ... } 這個配置塊的意圖是將所有匹配 /admin/ 開頭的路徑(包括 /admin//admin/*)的請求,轉發到後端應用程式,其地址為 http://b.com.tw
      • proxy_pass http://b.com.tw; 這個指令表示將符合條件的請求轉發給 http://b.com.tw 這個後端服務處理。
    2. /uploads//uploads/* 路徑的靜態檔案指向其他資料夾
      • location ^~ /uploads/ { ... } 這個配置塊的意圖是處理匹配 /uploads/ 開頭的路徑(包括 /uploads//uploads/*)的請求,並將這些請求指向伺服器上的一個具體的資料夾來提供靜態檔案。
      • alias /root-document/b.com.tw/uploads/; 這個指令表示將 /uploads/ 路徑的請求映射到伺服器上 /root-document/b.com.tw/uploads/ 目錄中的對應檔案。例如,請求 /uploads/image.jpg 會映射到 /root-document/b.com.tw/uploads/image.jpg
      • try_files $uri $uri/ /index.html; 這個指令會嘗試按順序查找以下檔案:
        • $uri:請求的原始檔案或目錄(例如 /root-document/b.com.tw/uploads/image.jpg)。
        • $uri/:如果是目錄,則查找目錄下的檔案(例如 /root-document/b.com.tw/uploads/image.jpg/)。
        • 如果以上都未找到,則回退到 /index.html 這個檔案。

    注意事項

    1. ^~ 前綴
      • ^~ 表示如果路徑匹配 /admin//uploads/,那麼該配置塊將優先於其他正則表達式匹配(例如 location ~location /)來處理請求。這確保了 /admin//uploads/ 的請求被這些特定的配置塊處理。
    2. Proxy Pass 的上下文
      • 當使用 proxy_pass 指令時,Nginx 將請求轉發給後端服務(如 http://b.com.tw)。確保 b.com.tw 這個服務能夠正確處理接收到的 /admin/ 路徑,並且能夠返回正確的響應。
    3. Alias 的使用
      • alias 指令用於將 URL 路徑映射到文件系統上的實際路徑,注意它不同於 root 指令。使用 alias 時需要確保映射的目錄結構和權限設置正確,以便 Nginx 能夠讀取和提供靜態檔案。
    4. 靜態檔案的優先級
      • /uploads/ 路徑的靜態檔案配置中,try_files 的指令順序很重要。你需要確保 /index.html 是你希望用來處理靜態資源請求失敗時的回退頁面。
    5. 安全性考量
      • 在提供靜態資源時,應確保 /root-document/b.com.tw/uploads/ 資料夾內的檔案不包含敏感信息,且檔案權限設置得當,防止未經授權的訪問。

    這段配置主要是為了處理特定路徑的請求,將動態內容轉發給後端應用程式,並通過靜態資源提供功能來處理文件的提供。

  • 使用 Nginx 設定通過 Cloudflare 的真實 IP 與只允許 Cloudflare IP 來的流量。

    使用 Nginx 設定通過 Cloudflare 的真實 IP 與只允許 Cloudflare IP 來的流量。

    一次講兩件事,都是和 Cloudflare 的 IP 有關。

    首先是在Ngnix 中,設定只允許 Cloudflare IP 來的流量。幾點注意:

    1. 需確認 Nginx 設定的網域有沒有通過 Cloudflare 的 Proxy,也就是看 DNS 設定中,橘色的雲有沒有亮起。
    2. 一樣的設定可以套用在其他有 Proxy/VPN/CDN 等操作上。組合拳是:流量走我的,其他檔下來。
    3. 同樣的組合拳也可以設定在單一允許 ip 的 api service 上面,不過請注意邏輯層與系統層的拆分,別被自己的 code 搞死了。
    4. Cloudflare 的 ips 是會更新的,請參考這裡
    5. 如果你有用 crontab 執行 url 的話記得也要把 allow 補進去。例如: allow 127.0.0.1; 或是改成 cli 的操作(推薦)。
    allow 173.245.48.0/20;
    allow 103.21.244.0/22;
    allow 103.22.200.0/22;
    allow 103.31.4.0/22;
    allow 141.101.64.0/18;
    allow 108.162.192.0/18;
    allow 190.93.240.0/20;
    allow 188.114.96.0/20;
    allow 197.234.240.0/22;
    allow 198.41.128.0/17;
    allow 162.158.0.0/15;
    allow 104.16.0.0/13;
    allow 104.24.0.0/14;
    allow 172.64.0.0/13;
    allow 131.0.72.0/22;
    
    allow 2400:cb00::/32;
    allow 2606:4700::/32;
    allow 2803:f800::/32;
    allow 2405:b500::/32;
    allow 2405:8100::/32;
    allow 2a06:98c0::/29;
    allow 2c0f:f248::/32;
    
    deny all; # deny all remaining ips

    再來是設定讓網站在通過 Cloudflare 之後,可以獲取到真實 ip 的設定,這部分我是抄網路的,有些覺得怪的地方,如果有理解錯誤還煩請指正。

    1. set_real_ip_from 是指信任的 proxy ip 所以要設定為 cloudflare 的 ip 段,標示這些來源的 ip 才能正確取得真實的 client ip。
    2. real_ip_header 是修改真實 ip 的 header 字段,默認是 X-Real-IP。改為 CF-Connecting-IP 是 cloudflare 在邊緣到您的來源 Web 伺服器的流量上傳送的標頭。請參考 Cloudflare 文件
    3. 上面提到的流量來源限制和 set_real_ip_from 的設置會衝突,不能一起設置 🫠
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    set_real_ip_from 2a06:98c0::/29;
    set_real_ip_from 2c0f:f248::/32;
    
    #use any of the following two
    
    real_ip_header CF-Connecting-IP;
    #real_ip_header X-Forwarded-For; # 滿多人用這個,不過 cf 有自己比較安全的標頭。

    同場加映 Cloudflare 的 ips 清單,更新頻率不高,不過設定上幾個注意:

    1. 相關 ips 的設定儘量統一管理。
    2. 有提供 api 可呼叫,參考這裡,如果要做自動化的人可以來弄弄。