使用 uWSGI、nginx、systemd 部署 Django
上一次很認真的 Django 部署記錄在《設定 Python 官方文件中文化自動更新 Server》一文。很巧地自己畢業的題目也要架個 Django 網站,所以就再跑了一次部署設定。舊文還提了有的沒的,這篇僅針對 Django 的部署。
這邊的部署設定都儘量不使用 root 權限,整個連線的流程圖如下:
nginx -- unix socket -- uWSGI -- Django
寫一個名為 PROJ.service
的 systemd unit 來管理這網站的啟動與否。之後 PROJ
就換成自己的專案名稱;USER
就換成執行網站的帳號。
作業系統
使用 Ubuntu 16.04 LTS。我對 Ubuntu 其實沒愛,但因為很多人用,畢業之後應該還找得到人維護。他跟 Debian 差不多,所以跟舊文沒什麼差別。Ubuntu 16 內建就有 Python 3.5,不用再裝;PostgreSQL 也來到 9.5 版。
使用 unattended-upgrades 定期更新與 security 相關的套件,它預設一天檢查一次,更新的記錄會在 /var/log/unattended-upgrades
目錄中。
PostgreSQL
參考《安裝 PostgreSQL 9 於 Debian Jessie / OSX》一文設定。建立跟 OS user 同名的 PostgreSQL 帳號,給了建立 database 的權限,這樣開發比較方便。不用設定密碼。
Django PROJ
使用內建 venv 在自己家目錄下某處,建立名為 VENV
的虛擬環境:
python3.5 -m venv VENV
有關部署的設定(即 settings.py
),利用 django-environ 把 secret key、database 連線資訊、寄信 SMTP server 等設定寫在獨立的檔案,就可以讓 local 和 production 環境讀到各自的設定。具體的做法可以參考 PyCon Taiwan 2016 網站管理設定 的寫法。
在連 PostgreSQL 時使用 local connection (Unix-domain socket),即使用者同名的身份。
DATABASE_URL=postgres:///TABLE_NAME
tmpfiles.d
把 nginx 與 uwsgi 溝通用的 socket 放在 /run/PROJ
底下,但這也表示重開機之後,/run/PROJ
資料夾就會消失不見,所以使用 tmpfiles.d1。除了資料夾的命名改成用專案名稱,設定都跟舊文一樣。
nginx
nginx 設定跟舊文一樣。放在 /etc/nginx/sites-available/PROJ.conf
# Upstream Django setting; the socket nginx connects to
upstream django {
server unix:///run/PROJ/django.sock;
}
server {
listen 80;
listen 443 default ssl;
server_name 123.123.123.123
;
charset utf-8;
client_max_body_size 10M; # max upload size
keepalive_timeout 15;
location /static {
alias /path/to/PROJ/assets;
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /etc/nginx/uwsgi_params;
}
}
/path/to/PROJ/assets
是 Django STATIC_ROOT 的路徑。只要執行 python manage.py collectstatic
後,即使 uWSGI 還沒設定就可以測試 /static/…/ 有沒有被 nginx 抓到。
啟動時,先把檔案連結到 /etc/nginx/site-enabled/
,重載 nginx 設定:
cd /etc/nginx/sites-enabled/
sudo ln -s ../sites-available/PROJ.conf .
sudo systemctl reload nginx
uWSGI
跟舊文最大的差別,只要裝在 VENV 裡面就好了;然後也不使用 emperor mode。寫一個 /etc/uwsgi/vassals/PROJ.ini
放設定:
[uwsgi]
chdir = /path/to/PROJ
# Django's wsgi file
module = PROJ.wsgi:application
env = DJANGO_SETTINGS_MODULE=PROJ.settings.production
# the virtualenv (full path)
home = /path/to/VENV
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 4
# the socket (use the full path to be safe
socket = /run/PROJ/django.sock
# ... with appropriate permissions - may be needed
chmod-socket = 664
uid = USER
gid = www-data
# clear environment on exit
vacuum = true
設定好後執行以下指令,就應該能看到網站能動了。
sudo /path/to/VENV/bin/uwsgi --ini /etc/uwsgi/vassals/PROJ.ini
systemd
這邊除了執行 uWSGI 的指令不同外,都跟舊文相同。Debian 系 systemd system unit 設定檔放在 /etc/systemd/system/PROJ.service
:
[Unit]
Description=PROJ's Django server by uWSGI
After=syslog.target
[Service]
ExecStart=/path/to/VENV/bin/uwsgi --ini /etc/uwsgi/vassals/PROJ.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
這邊設定它會(有錯誤時)自動重新起動,並把 stderr 導到 syslog。接著,就要啟動這個 PROJ.service
服務:
sudo systemctl enable PROJ
sudo systemctl status PROJ
可以透過 sudo journalctl -xe -u PROJ
來查看 uWSGI 執行、連線 log。
確認、總結
重啟系統一次,如果網站還活著,就表示一切設定都沒問題。整體上不太複雜,但權限不符的錯誤可能會讓你鬼打牆,要有耐心。
-
也可以用 systemd.exec(5) 提到的
RuntimeDirectory=PROJ
來建立執行用目錄。但因為PROJ.service
的 USER 必須是 root,這種情況 man page 就建議改用 tmpfiles.d。我覺得應該能解決使用 root 權限的問題,但太懶了就先這樣…… ↩