Blog Details

Linux 作業系統 cutexyz > Blog > 伺服器管理 > Nginx 如何做到 Reverse Proxy 反向代理

Nginx 如何做到 Reverse Proxy 反向代理

什麼事反向代理 reverse proxy, 什麼又是正向代理 proxy server, 請參考相關資源進行了解, 這篇就以實務操作來設定 nginx 進行反向代理為主!! 請各位讀者先了解一下作用原理在進行操作會更能了解箇中道理喔喔!!

事前準備工作

  1. 一個準備 “被” 代理的服務, 也就在 nginx 後端的服務, 等一下我們就準備用 python 寫一個小服務來代表
  2. 一個已經在運作的 nginx
  3. 一個指向 127.0.0.1 的 domain, 這邊我們準備一個 domain 叫做 local127.cutexyz.com 的 domain 「未來可能失效」

Part 1, 準備被代理的 http 服務, 服務位置為 http://127.0.0.1:9090

請在您的 ubuntu 內建裡此檔案, 好比說. /opt/myapp/pythonserver.py

#!/usr/bin/env python3
import http.server
import socketserver
from datetime import datetime

# 指定監聽 Port 為 9090
PORT = 9090
# 綁定 127.0.0.1 (Localhost Only),確保外部網路無法直接訪問,必須透過 Nginx 代理
HOST = "127.0.0.1"


class RealIPHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        # 1. 嘗試從 Header 中讀取由 Nginx 傳遞的真實 IP (X-Real-IP)
        client_ip = self.headers.get("X-Real-IP")
        if not client_ip:
            # 若無 X-Real-IP,則退回使用標準 Socket Remote IP
            client_ip = self.client_address[0]

        # 2. 獲取連線時間與 Host Header
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        host_header = self.headers.get("Host", "Unknown")

        # 3. 準備回應給前端/瀏覽器的 HTML 畫面
        response_content = f"""<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <title>Week 8 Demo Server</title>
    <style>
        body {{ font-family: Arial, sans-serif; background-color: #f4f6f9; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }}
        .card {{ background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); max-width: 500px; width: 100%; }}
        h1 {{ color: #2c3e50; font-size: 1.5rem; border-bottom: 2px solid #3498db; padding-bottom: 0.5rem; }}
        p {{ color: #34495e; line-height: 1.6; }}
        .highlight {{ color: #e74c3c; font-weight: bold; background: #fceae9; padding: 2px 6px; border-radius: 4px; }}
        .code {{ font-family: monospace; background: #ecf0f1; padding: 2px 4px; border-radius: 3px; }}
    </style>
</head>
<body>
    <div class="card">
        <h1>🎉 反向代理成功連線!</h1>
        <p><strong>服務回應 Port:</strong> <span class="code">9090</span></p>
        <p><strong>請求域名/Host:</strong> <span class="code">{host_header}</span></p>
        <p><strong>你的真實外網 IP:</strong> <span class="highlight">{client_ip}</span></p>
        <p><strong>伺服器時間:</strong> {current_time}</p>
    </div>
</body>
</html>
"""

        # 4. 發送 HTTP 200 OK 標頭
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(response_content.encode("utf-8"))))
        self.end_headers()

        # 5. 輸出內文
        self.wfile.write(response_content.encode("utf-8"))

        # 6. 在伺服器 Terminal 印出 Log(帶有真實 IP 辨識)
        print(
            f"[{current_time}] 收到來自真實 IP: {client_ip} 的 GET 請求 (Port 9090)"
        )


if __name__ == "__main__":
    # 使用 ThreadingHTTPServer 避免併發請求卡住
    with socketserver.TCPServer((HOST, PORT), RealIPHTTPRequestHandler) as httpd:
        print(f"🚀 Python HTTP 服務已啟動在 http://{HOST}:{PORT}")
        print("等待 Nginx 反向代理流量轉導中...")
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\n🛑 服務已停止")

完成後直接執行 python3 pythonserver.py 並確認沒有問題產生, 接下來 ctrl + c 結束後, 改用 python3 pythonserver.py & 讓他去背景執行, 因為接下來我們還有別的指令要進行.

Part 2, 進行 Nginx 服務的修改

首先我要知道 nginx 的設定檔目錄有兩個
/etc/nginx/sites-available/:站台設定檔儲藏室。所有寫好的站台設定都放在這裡。
/etc/nginx/sites-enabled/:已啟用的站台目錄。透過「軟連結 (Symbolic Link)」指向 sites-available 中的檔案,Nginx 只會讀取此處的設定。

接下來我們就實作看看, 假設我們有一個網站叫做 myapp, 實作的 SOP 如下

# 1. 在 available 建立設定檔, 副檔名 conf 可加可不加
sudo nano /etc/nginx/sites-available/myapp.conf

# my app.conf 內容
###############################################
server {
    listen 80;
    server_name local127.cutexyz.com; # 或伺服器 IP / 網域名稱

    # 存取日誌與錯誤日誌定位
    access_log /var/log/nginx/myapp_access.log;
    error_log /var/log/nginx/myapp_error.log;

    location / {
        # 1. 轉導目標:轉發給本機 8080 運作中的應用程式
        proxy_pass http://127.0.0.1:9090;

        # 2. 關鍵 Header 傳遞 (確保後端能拿到真實客戶端資訊)
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 3. 連線逾時設定 (選用)
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
    }
}
###############################################

# 2. 建立軟連結至 enabled 以啟用
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/

# 3. 測試設定檔語法是否正確 (極度重要!)
sudo nginx -t

# 4. 重新載入設定
sudo systemctl reload nginx

Part 3, 進行驗證與測試

# 首先可以透過 9090 port 觀看 python 服務使否啟動
# 如果你的 ubuntu 是安裝在 virtualbox 內, 記得要去設定 NAT 的 port 轉發喔!!
http://localhost:9090

# 接下來可以去設定 ufw 防火牆來把 9090 關閉, 這個時候再去以往只查看網站應該就會發現他不工作了
http://localhost:9090

# 那麼我們接下來就可以輸入我們設定好的環境來測測, 如果你可以看到跟剛剛 http://localhost:9090
# 一樣的內容, 那就代表你成功了喔!!
http://local127.cutexyz.com

Nginx 設定檔解說

Header 項目 語法設定 代表意義與作用
Host proxy_set_header Host $host; 將客戶端原本請求的域名/Host 傳給後端,避免後端轉址錯誤。
X-Real-IP proxy_set_header X-Real-IP $remote_addr; 將連線至 Nginx 的真實客戶端外網 IP 填寫進去,供後端辨識。
X-Forwarded-For proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 紀錄經過的所有代理伺服器 IP 鏈條,適合多層代理分析。
X-Forwarded-Proto proxy_set_header X-Forwarded-Proto $scheme; 告知後端客戶端使用的是 http 還是 https 協定。

Leave A Comment

All fields marked with an asterisk (*) are required