Django 生產部署:Nginx + Gunicorn 完全指南 | Django 教學
從開發環境的
python manage.py runserver到真正面對使用者的生產服務,中間隔著一道巨大的鴻溝。生產部署需要 Gunicorn 作為 WSGI(Web Server Gateway Interface) 應用伺服器來處理並發請求,再由 Nginx 擔任 反向代理(Reverse Proxy) 處理靜態檔案、SSL 終止與負載平衡。本篇將完整走過 Django 生產部署的標準架構,從安裝設定到上線檢查,帶你打造穩定高效的生產環境。
為什麼需要反向代理?
Django 內建的開發伺服器(runserver)是為了方便開發而設計的,它有幾個致命的限制:
| 特性 | 開發伺服器(runserver) | 生產架構(Nginx + Gunicorn) |
|---|---|---|
| 並發處理 | 單執行緒,一次一個請求 | 多 Worker 並發處理 |
| 靜態檔案 | 效率極低,不支援快取 | Nginx 直接服務,支援快取與壓縮 |
| SSL/TLS | 不支援 | Nginx 處理 SSL 終止 |
| 安全性 | 無防護機制 | 限制請求大小、防止慢速攻擊 |
| 程序管理 | 無自動重啟 | Worker 崩潰自動重啟 |
| 效能 | 僅供開發使用 | 生產級效能 |
生產部署的標準架構如下:
Internet(使用者)
↓
[Nginx] ← 靜態檔案服務、SSL 終止、反向代理
↓
[Gunicorn / Uvicorn] ← WSGI/ASGI 應用伺服器,管理 Worker 程序
↓
[Django Application] ← 業務邏輯處理
↓
[PostgreSQL] + [Redis] ← 資料庫 + 快取
每一層各司其職:Nginx 處理網路層的事務,Gunicorn 管理應用程序,Django 專注於業務邏輯。
Gunicorn 安裝與基本設定
Gunicorn(Green Unicorn) 是 Python 生態系中最成熟的 WSGI HTTP 伺服器,採用 Pre-fork Worker Model(預先 fork 工作程序模型) ,在啟動時由 Master 程序預先 fork 出多個 Worker 程序,每個 Worker 獨立處理請求。
安裝 Gunicorn
# 安裝 Gunicorn
pip install gunicorn
# 確認安裝成功
gunicorn --version
基本啟動指令
# 最簡單的啟動方式
gunicorn myproject.wsgi:application
# 指定 Worker 數量與綁定位址
gunicorn myproject.wsgi:application --workers 4 --bind 0.0.0.0:8000
# 搭配常用參數
gunicorn myproject.wsgi:application \
--workers 4 \
--worker-class gthread \
--threads 2 \
--bind unix:/run/gunicorn.sock \
--timeout 30
Gunicorn Worker 配置詳解
Worker 的配置直接影響應用的並發能力與資源使用效率,是 Gunicorn 調校的核心。
Worker 類型選擇
| Worker 類型 | 說明 | 適用情境 |
|---|---|---|
sync(預設) | 同步 Worker,每個 Worker 一次處理一個請求 | 一般 Django 應用、CPU 密集型任務 |
gthread | 多執行緒同步 Worker | I/O 等待較多的場景 |
gevent | 基於 gevent 的協程 Worker | 大量 I/O 等待、高並發連線 |
uvicorn.workers.UvicornWorker | ASGI Worker,整合 Uvicorn | async 視圖、WebSocket |
Worker 數量建議
官方建議公式為 CPU 核心數 x 2 + 1:
import multiprocessing
# 例如 4 核心伺服器:4 x 2 + 1 = 9 個 Workers
workers = multiprocessing.cpu_count() * 2 + 1
如果使用 gthread Worker,總並發量等於 workers x threads。例如 4 Workers 搭配 4 threads,可同時處理 16 個請求。
gunicorn.conf.py 設定檔
將所有設定集中到設定檔,便於版本控制與管理:
# gunicorn.conf.py
import multiprocessing
# === Worker 設定 ===
workers = multiprocessing.cpu_count() * 2 + 1 # Worker 數量
worker_class = 'sync' # Worker 類型(預設同步)
threads = 2 # 每個 Worker 的執行緒數
timeout = 30 # Worker 靜默超時秒數(超時強制重啟)
graceful_timeout = 30 # 優雅關閉等待秒數
keepalive = 5 # Keep-alive 連線秒數
# === 綁定設定 ===
bind = '0.0.0.0:8000' # 綁定位址與端口
# === 日誌設定 ===
accesslog = '/var/log/gunicorn/access.log' # 存取日誌路徑
errorlog = '/var/log/gunicorn/error.log' # 錯誤日誌路徑
loglevel = 'info' # 日誌等級
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
# === 安全設定 ===
limit_request_line = 4096 # 請求行最大長度
limit_request_fields = 100 # 請求標頭欄位最大數量
# === 程序管理 ===
pidfile = '/tmp/gunicorn.pid' # PID 檔案路徑
daemon = False # 是否以 daemon 模式執行(使用 Systemd 時設 False)
使用設定檔啟動:
gunicorn myproject.wsgi:application -c gunicorn.conf.py
Nginx 反向代理設定
Nginx 是高效能的 HTTP 伺服器與反向代理伺服器,在 Django 生產架構中負責接收外部請求、服務靜態檔案、處理 SSL 終止,並將動態請求轉發給 Gunicorn。
安裝 Nginx
# Ubuntu / Debian
sudo apt update
sudo apt install nginx
# 啟動 Nginx
sudo systemctl start nginx
sudo systemctl enable nginx
完整 Nginx 設定檔
# /etc/nginx/sites-available/myapp.conf
# 定義上游 Gunicorn 伺服器
upstream django_app {
server 127.0.0.1:8000;
# 多個 Gunicorn 實例可做負載平衡
# server 127.0.0.1:8001;
# server 127.0.0.1:8002;
}
# HTTP → HTTPS 強制重導向
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
# HTTPS 主設定
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL 憑證設定(Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 靜態檔案(直接由 Nginx 服務,不經過 Gunicorn)
location /static/ {
alias /var/www/myapp/staticfiles/;
expires 30d; # 瀏覽器快取 30 天
add_header Cache-Control "public, immutable";
}
# 媒體檔案
location /media/ {
alias /var/www/myapp/media/;
expires 7d;
}
# 反向代理至 Gunicorn
location / {
proxy_pass http://django_app;
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;
proxy_read_timeout 90;
proxy_connect_timeout 90;
client_max_body_size 20M; # 上傳檔案大小限制
}
}
啟用站台設定
# 建立 symbolic link 啟用站台
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
# 測試設定檔語法
sudo nginx -t
# 重新載入 Nginx
sudo systemctl reload nginx
靜態檔案與媒體檔案服務
在生產環境中,靜態檔案不應該由 Django 處理,而是交給 Nginx 直接服務,效能差距可達數十倍。
收集靜態檔案
# 將所有靜態檔案收集到 STATIC_ROOT 目錄
python manage.py collectstatic --noinput
# settings.py(生產環境設定)
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/myapp/staticfiles/' # collectstatic 輸出目錄
MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/myapp/media/' # 使用者上傳檔案目錄
靜態檔案服務策略比較
策略 1:Nginx 直接服務(最佳效能)
→ collectstatic → /var/www/myapp/staticfiles/ → Nginx location /static/
適用:傳統伺服器部署
策略 2:WhiteNoise(簡化部署,無需額外 Nginx 設定)
→ WhiteNoise Middleware 直接從 Django 服務,支援 Gzip + ETag
適用:PaaS 平台(Heroku、Render)
策略 3:CDN(全球分發,大流量首選)
→ collectstatic → 上傳 S3/GCS → CloudFront/Cloud CDN
適用:全球用戶、高流量網站
Uvicorn 作為 ASGI 替代方案
如果你的 Django 專案使用了 非同步視圖(async def view) 或 Django Channels(WebSocket) ,就需要 ASGI(Asynchronous Server Gateway Interface) 伺服器。 Uvicorn 是目前最受歡迎的 Python ASGI 伺服器,基於 uvloop 與 httptools 構建,效能表現優異。
WSGI vs ASGI 選擇
| 特性 | WSGI(Gunicorn) | ASGI(Uvicorn) |
|---|---|---|
| 同步 View | 完整支援 | 完整支援 |
| 非同步 View(async def) | 不支援 | 支援 |
| WebSocket | 不支援 | 支援 |
| 成熟度 | 非常成熟,生產首選 | 較新,活躍發展中 |
| 推薦場景 | 純 REST API、傳統 Web | WebSocket、SSE、async I/O |
安裝與啟動 Uvicorn
# 安裝 Uvicorn(含高效能依賴)
pip install uvicorn[standard]
# 開發環境啟動(自動重載)
uvicorn myproject.asgi:application --reload --host 0.0.0.0 --port 8000
生產環境:Gunicorn + UvicornWorker
在生產環境中,建議以 Gunicorn 作為程序管理器搭配 UvicornWorker,兼得兩者優勢:
# Gunicorn 管理 Uvicorn Worker
gunicorn myproject.asgi:application \
-k uvicorn.workers.UvicornWorker \
--workers 4 \
--bind 0.0.0.0:8000
部署架構變為:
用戶端 → Nginx → Gunicorn(Master)→ UvicornWorker x N → Django ASGI
SSL/TLS 設定(Let’s Encrypt + Certbot)
Let’s Encrypt 提供免費的 SSL/TLS 憑證, Certbot 是其官方的自動化工具,能自動申請、安裝與續期憑證。
安裝 Certbot
# Ubuntu / Debian
sudo apt install certbot python3-certbot-nginx
申請憑證
# 自動為 Nginx 申請並設定 SSL 憑證
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# 或只申請憑證,手動設定 Nginx
sudo certbot certonly --webroot -w /var/www/myapp -d yourdomain.com
自動續期
Let’s Encrypt 憑證有效期為 90 天,Certbot 安裝後會自動設定定期續期:
# 測試自動續期
sudo certbot renew --dry-run
# 確認定時任務(systemd timer 或 cron)
sudo systemctl list-timers | grep certbot
Systemd 管理 Gunicorn
使用 Systemd 管理 Gunicorn 服務,可實現開機自動啟動、崩潰自動重啟與日誌整合。
建立 Gunicorn Socket 檔案
# /etc/systemd/system/gunicorn.socket
[Unit]
Description=Gunicorn Socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
建立 Gunicorn Service 檔案
# /etc/systemd/system/gunicorn.service
[Unit]
Description=Gunicorn daemon for Django Application
Requires=gunicorn.socket
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/var/www/myapp/venv/bin/gunicorn \
--access-logfile - \
--workers 4 \
--bind unix:/run/gunicorn.sock \
myproject.wsgi:application
Restart=on-failure
RestartSec=5s
Environment="DJANGO_SETTINGS_MODULE=myproject.settings.production"
[Install]
WantedBy=multi-user.target
啟動與管理
# 啟動 socket 與 service
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
# 查看服務狀態
sudo systemctl status gunicorn
# 重新啟動(部署新版本後)
sudo systemctl restart gunicorn
# 查看日誌
sudo journalctl -u gunicorn --since today
部署前檢查清單
Django 提供了 check --deploy 指令,可以自動檢查常見的安全與設定問題:
# 執行部署檢查
python manage.py check --deploy
關鍵設定項目
# settings/production.py
# === 安全性 ===
DEBUG = False # 絕對不可為 True
SECRET_KEY = config('DJANGO_SECRET_KEY') # 從環境變數讀取,不可寫死
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']
# CSRF 信任來源(Django 4.0+ 必須包含 scheme)
CSRF_TRUSTED_ORIGINS = [
'https://yourdomain.com',
'https://www.yourdomain.com',
]
# === HTTPS 相關 ===
SECURE_SSL_REDIRECT = True # HTTP 重導向至 HTTPS
SECURE_HSTS_SECONDS = 31536000 # HSTS 有效期一年
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SESSION_COOKIE_SECURE = True # Cookie 只透過 HTTPS 傳送
CSRF_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# === 靜態檔案 ===
STATIC_ROOT = '/var/www/myapp/staticfiles/'
MEDIA_ROOT = '/var/www/myapp/media/'
完整部署檢查清單
| 檢查項目 | 說明 |
|---|---|
DEBUG = False | 生產環境必須關閉 Debug 模式 |
SECRET_KEY 從環境變數讀取 | 不可寫死在程式碼中 |
ALLOWED_HOSTS 已設定 | 防止 HTTP Host Header 攻擊 |
collectstatic 已執行 | 靜態檔案已收集到 STATIC_ROOT |
資料庫已 migrate | 確保資料庫 schema 為最新 |
| SSL 憑證已安裝 | HTTPS 正常運作 |
| Systemd service 已啟用 | Gunicorn 開機自動啟動 |
| 日誌路徑已建立 | Gunicorn 與 Nginx 日誌目錄存在且有寫入權限 |
| 防火牆已設定 | 僅開放 80、443 port |
總結
Django 生產部署是從開發走向上線的關鍵一步,正確的架構設定能確保應用的穩定性、安全性與效能。以下整理本篇的重點:
- 開發伺服器不可用於生產 ——
runserver缺乏並發處理、安全防護與效能最佳化,生產環境必須使用 Gunicorn 等專業應用伺服器 - Gunicorn Worker 配置 是效能調校的核心——Worker 數量建議為 CPU 核心數 x 2 + 1,搭配
gunicorn.conf.py設定檔集中管理所有參數 - Nginx 反向代理 處理靜態檔案、SSL 終止與負載平衡——靜態檔案由 Nginx 直接服務,動態請求透過
proxy_pass轉發給 Gunicorn - Uvicorn 作為 ASGI 替代方案 ——當專案需要非同步視圖或 WebSocket 時,可使用 Gunicorn + UvicornWorker 的組合
- Let’s Encrypt + Certbot 提供免費 SSL 憑證——自動申請、安裝與續期,確保 HTTPS 安全連線
- Systemd 管理 Gunicorn 實現開機自動啟動與崩潰自動重啟——建立 socket 與 service 檔案即可完成設定
- 部署前檢查清單 確保所有安全與效能設定到位——使用
python manage.py check --deploy自動檢查常見問題
下一篇我們將深入探討 Django 的 進階資料庫操作 ,學習連線池、Raw SQL 查詢與交易管理等進階技術。