本文 AI 產出,尚未審核

FastAPI 部署與架構:HTTPS 與 Reverse Proxy


簡介

在開發完一個功能完整的 FastAPI 服務後,最關鍵的步驟往往是 安全地高效地 把它交付給使用者。
HTTP 本身是明文傳輸,若直接暴露在公網,資料會被竊聽、篡改,甚至遭受中間人攻擊 (MITM)。因此,HTTPS 已成為 Web 服務的基本門檻。

另一方面,單純用 uvicornhypercorn 直接對外提供服務會面臨 可擴充性、負載均衡、日誌管理 等限制。Reverse Proxy(反向代理)— 例如 Nginx、Traefik 或 Caddy — 能夠在應用程式與客戶端之間擔任「門面」角色,統一處理 TLS 終止、路由、緩衝、健康檢查等工作。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,帶領讀者一步步完成 FastAPI + HTTPS + Reverse Proxy 的完整部署流程,適合剛接觸部署的初學者,也能為中級開發者提供可直接套用的範本。


核心概念

1. 為什麼要在 Reverse Proxy 上終止 TLS

項目 直接在 FastAPI 終止 TLS 在 Reverse Proxy 終止 TLS
效能 每個 worker 都要處理加解密,CPU 負載較高 只由 Proxy 處理,加密成本集中,FastAPI 只負責業務邏輯
可擴充 每個實例需要自行管理憑證 憑證集中管理,新增/刪除 FastAPI 實例不影響 TLS
日誌 & 監控 需要自行實作 Proxy 可直接輸出存取日誌、統計
靜態檔案 需要在 FastAPI 中額外設定 Proxy 可直接提供,降低應用程式負擔

結論:在生產環境中,建議把 TLS 終止交給 Nginx (或其他 Reverse Proxy) 處理,FastAPI 僅保留純粹的 API 功能。

2. HTTPS 基礎流程

  1. Client → Proxy:客戶端發起 HTTPS 連線,TLS 握手在 Proxy 完成。
  2. Proxy → FastAPI:Proxy 以 HTTP (或 HTTP/2) 方式將請求轉發給 FastAPI。
  3. FastAPI → Proxy:FastAPI 回傳 JSON、HTML 等內容給 Proxy。
  4. Proxy → Client:Proxy 再以 TLS 加密的方式回傳給客戶端。

此流程不僅提升安全性,也讓 負載均衡藍綠部署金絲雀發布 等進階策略變得容易實現。

3. 常見的 Reverse Proxy 選型

Proxy 優點 缺點 常見使用情境
Nginx 成熟、模組豐富、支援高併發 配置語法較繁瑣 大多數傳統 Web、容器化部署
Traefik 內建 Docker/Kubernetes 自動發現、動態配置 功能較 Nginx 少 微服務、Docker‑Compose、K8s
Caddy 零配置自動取得 Let's Encrypt 社群較小 小型服務、開發環境

本文以 Nginx 為例,因其在企業環境中的佔有率最高,且提供完整的 TLS、緩衝與日誌功能。


程式碼範例

以下範例假設你已在本機或雲端 VM 安裝好 Python 3.10+uvicornnginx,並且有一個簡單的 FastAPI 應用。

1. 建立最小 FastAPI 應用

# app/main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    """
    回傳簡單的歡迎訊息,測試用
    """
    return {"message": "Hello, FastAPI with HTTPS & Reverse Proxy!"}

說明:此檔案只負責路由與業務邏輯, 包含任何 TLS 或 CORS 設定,讓 Proxy 完全掌控。

2. 使用 Uvicorn 以 --port 8000 啟動服務

# 在專案根目錄執行
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4

提示--workers 讓 Uvicorn 在多核 CPU 上產生多個 worker,提升吞吐量。

3. Nginx 設定:HTTP → HTTPS 重新導向、TLS 終止、反向代理

以下範例使用 自簽憑證(僅供測試),正式環境請改為 Let's Encrypt。

# /etc/nginx/conf.d/fastapi.conf
server {
    listen 80;
    server_name example.com www.example.com;

    # 1️⃣ 將所有 HTTP 請求永久重新導向至 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # 2️⃣ TLS 設定(使用自簽憑證)
    ssl_certificate     /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    # 3️⃣ 推薦的安全性參數
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 4️⃣ 反向代理設定
    location / {
        proxy_pass http://127.0.0.1:8000;          # 轉發至 FastAPI
        proxy_set_header Host $host;              # 保留原始 Host
        proxy_set_header X-Real-IP $remote_addr;  # 真實 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 5️⃣ 超時與緩衝設定(依需求調整)
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
        proxy_buffering off;   # 若需要即時串流可關閉緩衝
    }

    # 6️⃣ 靜態檔案示範(如果有 /static 目錄)
    location /static/ {
        alias /var/www/static/;
        expires 30d;
        add_header Cache-Control "public";
    }

    # 7️⃣ 訪問日誌(可自行指定格式)
    access_log /var/log/nginx/fastapi.access.log combined;
    error_log  /var/log/nginx/fastapi.error.log warn;
}

重點

  • proxy_set_header X-Forwarded-Proto $scheme; 讓 FastAPI 能辨識原始請求是 HTTPS,若需要在程式內判斷,可透過 request.headers["x-forwarded-proto"] 取得。
  • proxy_buffering off; 在需要 WebSocketServer‑Sent Events 時特別重要。

4. 產生自簽憑證(測試用)

# 建立憑證目錄
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -new -newkey rsa:2048 -days 365 -nodes \
    -x509 -keyout /etc/nginx/ssl/example.com.key \
    -out /etc/nginx/ssl/example.com.crt \
    -subj "/C=TW/ST=Taiwan/L=Taipei/O=MyCompany/OU=IT/CN=example.com"

說明-subj 直接指定憑證資訊,省去互動式輸入。正式環境請改用 Let's Encrypt(見第 5 範例)。

5. 使用 Certbot 取得 Let’s Encrypt 憑證(自動續期)

# 1️⃣ 安裝 Certbot(以 Ubuntu 為例)
sudo apt update
sudo apt install certbot python3-certbot-nginx -y

# 2️⃣ 執行取得憑證的指令
sudo certbot --nginx -d example.com -d www.example.com

# 3️⃣ 設定自動續期(已預設為 systemd timer)
sudo systemctl status certbot.timer

結果:Certbot 會自動在 Nginx 配置檔中加入 ssl_certificatessl_certificate_key,並設定 HTTP‑01 挑戰來驗證所有權。

6. Docker Compose 整合:FastAPI + Nginx + Certbot

# docker-compose.yml
version: "3.9"

services:
  api:
    build: .
    container_name: fastapi_app
    expose:
      - "8000"
    restart: unless-stopped

  nginx:
    image: nginx:stable-alpine
    container_name: nginx_proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - ./static:/var/www/static:ro
    depends_on:
      - api
    restart: unless-stopped

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - ./nginx/ssl:/etc/letsencrypt
      - ./nginx/conf.d:/etc/nginx/conf.d
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
    restart: unless-stopped

說明

  • api 只暴露內部埠 8000,不對外開放。
  • nginx 掛載自訂的設定與憑證目錄。
  • certbot永續執行 的方式每 12 小時檢查一次憑證續期。

常見陷阱與最佳實踐

陷阱 可能的結果 解決方案 / 最佳實踐
直接在 FastAPI 上使用 uvicorn --ssl-keyfile 每個 worker 都要載入憑證,CPU 負載升高,且憑證管理分散 將 TLS 終止交給 Reverse Proxy,FastAPI 只跑 HTTP
忘記在 Nginx 中加入 proxy_set_header X-Forwarded-Proto 應用程式內的 request.url.scheme 仍是 http,導致產生錯誤的絕對 URL(如 OAuth 回呼) 設定 X-Forwarded-Proto,或在 FastAPI 中使用 ForwardedHeaderMiddleware
使用自簽憑證卻未在瀏覽器信任 使用者會看到安全警告,影響體驗 在測試環境可自行信任根憑證;正式環境務必使用 Let's Encrypt 或商業 CA
Nginx 緩衝導致 WebSocket 斷線 前端即時通訊無法正常運作 location /ws/ 中加入 proxy_buffering off; 以及 proxy_http_version 1.1;
未設定 HTTP → HTTPS 重新導向 使用者仍可能透過 http 存取,資訊被明文傳輸 在 Nginx 中加入 return 301 https://$host$request_uri;
憑證更新失敗卻未監控 憑證過期導致服務中斷 設定 監控(如 Prometheus + Alertmanager)或使用 certbot renew --dry-run 定期測試

進階最佳實踐

  1. 使用 ForwardedHeaderMiddleware:讓 FastAPI 能自動解析 X-Forwarded-ProtoX-Forwarded-For

    # app/main.py
    from fastapi import FastAPI
    from starlette.middleware.proxy_headers import ProxyHeadersMiddleware
    
    app = FastAPI()
    app.add_middleware(ProxyHeadersMiddleware)   # 解析 X-Forwarded-* 標頭
    
  2. 啟用 HTTP/2:在 Nginx listen 443 ssl http2; 可提升多路徑效能,特別是前端 SPA 與 API 同時使用時。

  3. 限制 HTTP 方法:在 Nginx 中使用 limit_except GET POST 限制不必要的方法,減少攻擊面。

  4. 安全標頭:加入 Strict-Transport-SecurityX-Content-Type-OptionsX-Frame-Options 等。

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    
  5. 日誌分割:依服務或環境 (dev / prod) 分開存取日誌,便於排錯與合規。


實際應用場景

場景 為何需要 HTTPS + Reverse Proxy 部署建議
企業內部 API Gateway 內部服務間仍需保護敏感資料,且需要統一認證、限流 使用 Nginx 作為 API Gateway,搭配 JWT 或 OAuth2,FastAPI 作為微服務
公開的 SaaS 平台 必須符合 PCI‑DSS、GDPR 等法規,提供安全的金流與個資傳輸 使用 Let’s Encrypt 自動憑證,Nginx 前端負載均衡,多個 FastAPI 實例 (Docker Swarm / Kubernetes)
IoT 裝置遠端管理 裝置只能使用 HTTP,必須在雲端做 TLS 終止,減少裝置負擔 Nginx 代理並使用 client certificate authentication,FastAPI 處理指令與資料庫寫入
WebSocket 即時聊天 需要雙向通訊且不能被中間人竊聽 Nginx 以 proxy_http_version 1.1proxy_set_header Upgrade $http_upgradeproxy_set_header Connection "upgrade" 轉發 WebSocket,仍保留 TLS 終止在前端

總結

  • HTTPS 為保護資料傳輸的根本,Reverse Proxy(以 Nginx 為例)則提供 TLS 終止、負載均衡、日誌與安全標頭 等關鍵功能。
  • FastAPI 中保持 「純粹的業務邏輯」,不在程式碼層面處理 TLS,能讓部署更彈性、維護成本更低。
  • 透過 proxy_set_headerForwardedHeaderMiddleware 等機制,確保 FastAPI 能正確感知原始協議與客戶端資訊。
  • 自簽憑證 只適合測試,正式環境強烈建議使用 Let’s Encrypt 或商業 CA,並設定自動續期。
  • 常見陷阱包括 TLS 重複終止、標頭遺漏、緩衝導致 WebSocket 異常,只要遵循本文的 最佳實踐,即可快速上線安全、可擴充的 FastAPI 服務。

藉由上述步驟,你已具備在 生產環境 中部署 FastAPI + HTTPS + Reverse Proxy 的完整能力,接下來只要根據實際流量與業務需求,調整 Nginx 的緩衝、限流與負載均衡策略,即可打造穩定且安全的 API 平台。祝開發順利!