[Django] 在Ubuntu中運用Nginx、Gunicorn 架設 Django API Server

原文於此

Tsung-Yu
Tom’s blog
10 min readJul 19, 2020

--

前言

目前正在進行一個Side Project,用朋友開給我的虛擬機(VM)架設一台API Server,趁還有記憶時趕快來筆記一下。

前置作業:

  • OS: Ubuntu 18.04
  • Web Framework: Django 3.0; djangorestframework 3.11
  • Server: Nginx 1.14
  • Database: MySQL

實作

架構圖

安裝環境

安裝所需要的環境,會下載python3、mysql、nginx

sudo apt-get update
sudo apt-get install python3-pip python3-dev mysql-server libmysqlclient-dev nginx

資料庫

sudo mysql_install_db
sudo mysql_secure_installation

執行上述指令進行初始化,系統會詢問一些相關設定,可以全部都採預設的方式。其中,要設定root權限的密碼,設定完之後執行下方指令登入root帳號

mysql -u root -p

完成登入便會進入MySQL Shell,在Shell中寫下腳本建立資料庫

CREATE DATABASE <yourprojectname> CHARACTER SET UTF8;

將上述的<yourprojectname>替換成自己要建立的資料庫名稱,其中utf8為Django預設得編碼。

接著是在MySQL中建立另一個User,建議之後都使用User的帳號來登入資料庫!

CREATE USER <yourdbuser>@localhost IDENTIFIED BY '<password>';

上述指令中,<yourdbuser>為自訂的User名稱,<password>為自訂的密碼,注意密碼要以字串的形式撰寫(要有'')。

GRANT ALL PRIVILEGES ON <yourprojectname>.* TO <yourdbuser>@localhost;

執行上述指令,賦予剛建立的User訪問資料庫的權限。

FLUSH PRIVILEGES;
exit

專案

下載相依套件

sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv

如果先前在Github上的repo已經有專案,可以直接Clone到Ubuntu的環境中

git clone repoAddress

或是直接在Ubuntu中建立新的專案

mkdir ~/<yourprojectdir>
cd ~/<yourprojectdir>

在專案資料夾中建立虛擬環境

virtualenv <yourenv>

啟動虛擬環境

source <yourenv>/bin/activate

以我為例,我的虛擬環境名稱為env

啟動虛擬環境後會看到終端機的最左方有的(env)表示啟動虛擬環境,若要退出虛擬環境則執行deactive

下載專案所需的相依套件

pip3 install django gunicorn pymysql djangorestframework

建立Django restframework的手把手教學可以參考官網範例

本文是直接Clone之前已經在Github建立好的Repo,建立Django專案的部分便不多加詳述,主要是紀錄部署到實際環境需要修改的設定。

到Django主要專案的資料夾下,建立一個名為__init__.py的檔案

vim __init__.py

寫下下方程式碼
__init__.py

import pymysql
pymysql.version_info = (1, 3, 13, "final", 0)
pymysql.install_as_MySQLdb()

寫完上述程式碼後儲存離開ESC+:wq!
接著在settings.py中做下方幾個更改

vim settings.py

settings.py

ALLOWED_HOSTS = [ 'domain.com', '<yourserverip>', 'localhost']# 此數將預設的SQLite替換成MySQL
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '<yourdatabasename>', # 資料庫名稱
'USER': '<yourdbuser>', # 資料庫使用者帳號
'PASSWORD': '<password>', # 資料庫密碼
'HOST': 'localhost', # 主機位置
'PORT': '3306',
}
}
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

寫完上述程式碼後儲存離開ESC+:wq!
ALLOWED_HOSTS為網域名稱、IP,還有設定連接Mysql資料庫,輸入剛才前面設定資料時,建立的資料庫名稱、使用者帳號、密碼。最後是STATIC_ROOT為設定靜態資源的根路徑。

執行

python3 manage.py collectstatic

執行下方指令進行資料庫遷移

python3 manage.py makemigrations
python3 manage.py migrate

gunicorn

下載gunicorn這個套件

pip3 install gunicorn

使用gunicorn測試Server

cd ~/<yourprojectdir>
gunicorn --bind 0.0.0.0:8000 <yourproject>.wsgi

成功後會看到下方畫面

接著訪問你的伺服器IP加上Port號即可查看目前運作狀況,如xxx.xxx.xx.xx:8000
跳出當前虛擬環境

deactivate

設定gunicorn

建立gunicorn.socket

sudo vim /etc/systemd/system/gunicorn.socket

檔案寫入

[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target

寫完上述程式碼後儲存離開ESC+:wq!

確認一下gunicorn的位置,因為後續建立gunicorn.service檔時會使用到

which gunicorn

執行上述指令會回傳gunicorn的路徑

建立gunicorn.service

sudo vim /etc/systemd/system/gunicorn.service

gunicorn.service
檔案寫入

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=<youruser> # 此處輸入這台機器的使用者名
Group=www-data
WorkingDirectory=<path/to/yourprojectdir> # 輸入Django專案的路徑
ExecStart=<gunicorn_path> \ # 輸入gunicorn的路徑
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
<yourproject>.wsgi:application
[Install]
WantedBy=multi-user.target

寫完上述程式碼後儲存離開ESC+:wq!
啟用 Gunicorn socket

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

檢查Gunicorn socket是否運作成功

sudo systemctl status gunicorn.socket

成功會顯示綠色active字樣

檢查gunicorn.sock 檔案是否存在/run這個資料夾中

file /run/gunicorn.sock

如果發現沒有在/run這個資料夾中,或是有其他問題,可以執行下方指令查看Log找問題

sudo journalctl -u gunicorn.socket

測試Server運作情況

sudo systemctl status gunicorn

或是發Curl測試

curl --unix-socket /run/gunicorn.sock localhost

回傳結果為HTML格式的資料
要對gunicorn排查問題也可以執行下方指令看Log

sudo journalctl -u gunicorn

若遇到問題,且查看Log後將問題排除,需要再重新run一次gunicorn

sudo systemctl daemon-reload
sudo systemctl restart gunicorn

配置Nginx代理傳給Gunicorn

sudo vim /etc/nginx/sites-available/project_name.conf

project_name修改為專案名稱
project_name.conf

server {
listen 80;
server_name <domain_name> <server_ip>; # 此處輸入網域名及ip,兩者以空格隔開。
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root <your_static_root_path>; # static的根目錄位置
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}

將檔案連結到啟動網站的目錄來啟動該檔案

sudo ln -s /etc/nginx/sites-available/project_name.conf /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx

設防火牆需要開放80 port上的流量,並刪除8000 port,禁止訪問。

sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'

建立成功!

--

--