FastAPI 部署與架構:HTTPS 與 Reverse Proxy
簡介
在開發完一個功能完整的 FastAPI 服務後,最關鍵的步驟往往是 安全地、高效地 把它交付給使用者。
HTTP 本身是明文傳輸,若直接暴露在公網,資料會被竊聽、篡改,甚至遭受中間人攻擊 (MITM)。因此,HTTPS 已成為 Web 服務的基本門檻。
另一方面,單純用 uvicorn 或 hypercorn 直接對外提供服務會面臨 可擴充性、負載均衡、日誌管理 等限制。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 基礎流程
- Client → Proxy:客戶端發起 HTTPS 連線,TLS 握手在 Proxy 完成。
- Proxy → FastAPI:Proxy 以 HTTP (或 HTTP/2) 方式將請求轉發給 FastAPI。
- FastAPI → Proxy:FastAPI 回傳 JSON、HTML 等內容給 Proxy。
- 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+、uvicorn、nginx,並且有一個簡單的 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;在需要 WebSocket 或 Server‑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_certificate與ssl_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 定期測試 |
進階最佳實踐
使用
ForwardedHeaderMiddleware:讓 FastAPI 能自動解析X-Forwarded-Proto、X-Forwarded-For。# app/main.py from fastapi import FastAPI from starlette.middleware.proxy_headers import ProxyHeadersMiddleware app = FastAPI() app.add_middleware(ProxyHeadersMiddleware) # 解析 X-Forwarded-* 標頭啟用 HTTP/2:在 Nginx
listen 443 ssl http2;可提升多路徑效能,特別是前端 SPA 與 API 同時使用時。限制 HTTP 方法:在 Nginx 中使用
limit_except GET POST限制不必要的方法,減少攻擊面。安全標頭:加入
Strict-Transport-Security、X-Content-Type-Options、X-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;日誌分割:依服務或環境 (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.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" 轉發 WebSocket,仍保留 TLS 終止在前端 |
總結
- HTTPS 為保護資料傳輸的根本,Reverse Proxy(以 Nginx 為例)則提供 TLS 終止、負載均衡、日誌與安全標頭 等關鍵功能。
- 在 FastAPI 中保持 「純粹的業務邏輯」,不在程式碼層面處理 TLS,能讓部署更彈性、維護成本更低。
- 透過
proxy_set_header、ForwardedHeaderMiddleware等機制,確保 FastAPI 能正確感知原始協議與客戶端資訊。 - 自簽憑證 只適合測試,正式環境強烈建議使用 Let’s Encrypt 或商業 CA,並設定自動續期。
- 常見陷阱包括 TLS 重複終止、標頭遺漏、緩衝導致 WebSocket 異常,只要遵循本文的 最佳實踐,即可快速上線安全、可擴充的 FastAPI 服務。
藉由上述步驟,你已具備在 生產環境 中部署 FastAPI + HTTPS + Reverse Proxy 的完整能力,接下來只要根據實際流量與業務需求,調整 Nginx 的緩衝、限流與負載均衡策略,即可打造穩定且安全的 API 平台。祝開發順利!