# 前言

本篇著重在從開發環境切換至 uWSGI 正式環境需改動的地方,而不是從 0 開始,所以會更精簡,詳細從開始部署以及更詳細的參數解釋可參考

透過 Nginx 部署 Django 至私有主機

# Django 開發伺服器轉向 uWSGI 的優點

Django 的 python manage.py runserver 是一個開發伺服器,而 uWSGI 是生產級別(Production Deployment)的應用伺服器

使用 uWSGI 而不是開發伺服器的原因:

  1. 性能優化:uWSGI 可生成多個工作進程來將傳入的請求並行化到多個 CPU 核心,才能處理高流量網站。
  2. 安全性更高:Django 開發伺服器未經過安全審核或性能測試,不適合在生產環境中使用
  3. 處理並行請求:uWSGI 運行在客戶端-伺服器模型上,網絡伺服器(如 nginx、Apache)與 django-uwsgi "工作進程"通信以提供動態內容,能更處理多個同時請求。
  4. 可配置性:uWSGI 支持多種配置選項,包括主從模式、進程數量控制、優雅重啟、資源限制等 Django 專案,適合不同的部署需求。
  5. 資源管理:使用 uWSGI 可以控制內存洩漏、物理內存問題和響應時間問題,有效管理系統資源。

簡而言之,開發伺服器是單線程的,而 uWSGI 可以使用多進程多線程,處理高流量或同時多個請求時性能更好

# 更改網頁伺服器 Nginx 的配置

編輯 /etc/nginx/sites-available 底下的對應 kostec.conf 檔案,在 /api//admin/ 路徑下需要進行相同的變更

將開發環境的配置註釋掉或移除,改成 uWSGI 的配置:

location /api/ {
  # 註釋或移除開發環境配置
  # proxy_pass http://127.0.0.1:8000;
  # proxy_set_header Host $host;
  # ...其他 proxy 配置...

  # 取消註釋 uWSGI 配置
  include /home/httpd/kostec/uwsgi_params;
  uwsgi_pass unix:/home/httpd/kostec/kostec.sock;
  uwsgi_read_timeout 30;
  uwsgi_send_timeout 30;
  uwsgi_param SCRIPT_NAME "";
  uwsgi_modifier1 30;
}

# 創建 uwsgi_params 檔案

在專案目錄下 /home/httpd/kostec/ 確保有 uwsgi_params 檔案以及內容包含:

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

# 更新 uWSGI 配置檔

[uwsgi]
# Django 相關配置
chdir = /home/httpd/kostec/backend
module = kostec.wsgi:application
env = DJANGO_SETTINGS_MODULE=kostec.settings

# 使用者和群組權限
uid = www-data
gid = www-data

# 連接選項
socket = /home/httpd/kostec/kostec.sock
chmod-socket = 666
vacuum = true

# 進程選項
master = true
processes = 4
threads = 2

# 效能優化
harakiri = 30
max-requests = 5000
buffer-size = 32768

# 日誌
logto = /var/log/uwsgi/kostec.log
log-reopen = true
log-slow = 1000

# 自動重啟
touch-reload = /home/httpd/kostec/backend/kostec/wsgi.py

# 啟動選項
daemonize = /var/log/uwsgi/kostec.log
pidfile = /tmp/kostec-master.pid

這邊我自己會把「使用者和群組權限」及 「日誌」的部分刪除,因為我習慣直接在終端機上查看錯誤

因此我的最終版本如下:

[uwsgi]
# Django 相關配置
chdir = /home/httpd/kostec/backend
# 確保這裡指向 Django 的 wsgi.py
module = backend.wsgi:application
virtualenv = /home/httpd/kostec/venv
env = DJANGO_SETTINGS_MODULE=backend.settings

# 連接配置
socket = /home/httpd/kostec/kostec.sock
chmod-socket = 666
vacuum = true
die-on-term = true
enable-threads = true

# 進程選項
master = true
processes = 5
threads = 2

# 效能優化
harakiri = 30
max-requests = 5000
buffer-size = 32768

# 自動重啟
touch-reload = /home/httpd/kostec/backend/backend/wsgi.py

# 日誌配置,uWSGI 將自動在背景運行,同時也會將輸出日誌寫入指定文件,並將進程 ID 保存到 pidfile 中,便於之後管理
daemonize = /home/httpd/kostec/uwsgi.log
pidfile = /home/httpd/kostec/uwsgi.pid

# 設置 systemd 服務管理 uWSGI

/etc/systemd/system 目錄下創建 kostec-uwsgi.service,並添加以下內容:

[Unit]
Description=uWSGI instance to serve Kostec
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/httpd/kostec/backend
ExecStart=/usr/local/bin/uwsgi --ini /home/httpd/kostec/kostec_uwsgi.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

然後試試啟用並啟動服務:

sudo systemctl enable kostec-uwsgi
sudo systemctl start kostec-uwsgi

# 成功

若一切順利,執行 sudo systemctl start kostec-uwsgi 應會看到以下的輸出,表示 uWSGI 服務已經成功啟動並運行中

service_active

然後網站也能正常接收到後端的請求,正常運行了。

# 常見錯誤 - 模組名稱導入錯誤

sudo systemctl start kostec-uwsgi 啟動 uWSGI 服務時,若出現以下錯誤:

no_module_error

一般就是 uwsgi.ini 檔案中的 moduleenv 參數設置錯誤,要確保它指向正確的 Django 應用程式模組

因為我的 Django 專案項目的主文件夾名稱是 backend,所以應該改成:

wsgi_dir

# 原本會導致錯的情況:
# env = DJANGO_SETTINGS_MODULE=kostec.settings

env = DJANGO_SETTINGS_MODULE=backend.settings

# 預部署檢查清單

從開發環境轉向生產環境部署完成後,可以執行 Django 的部署檢查,他會印出一些建議的配置和注意事項,確保 Django 在正式運營環境中正常運作

python manage.py check --deploy

# 手動創建存放錯誤訊息的日誌目錄和檔案(非必要)

# 創建日誌目錄
sudo mkdir -p /var/log/uwsgi

# 創建日誌檔案
sudo touch /var/log/uwsgi/kostec.log

# 假設 uWSGI 以 www-data 用戶運行
sudo chown -R www-data:www-data /var/log/uwsgi
sudo chmod 755 /var/log/uwsgi
sudo chmod 644 /var/log/uwsgi/kostec.log

# 設置目錄和檔案的擁有者和權限,確保 uWSGI 進程可以寫入
sudo chown -R $(whoami):$(whoami) /var/log/uwsgi

# 停止 uWSGI 服務

systemctl 停止 uWSGI 服務時可能很慢,這是因為 systemd 預設會嘗試優雅地關閉服務,給程序時間完成當前請求並清理資源。以下是一些更快速停止 uWSGI 的方法

sudo systemctl stop kostec-uwsgi

暴力停止 uWSGI 服務,直接使用 Linux SIGTERM 信號

sudo pkill -f uwsgi

請我喝[茶]~( ̄▽ ̄)~*

Young 微信支付

微信支付

Young 支付寶

支付寶