14 - 使用 Nginx 和 Gunicorn 部署 Django 部落格

追夢人物發表於2017-05-18

我們部落格的基礎功能已經開發的基本差不多了,雖然還有很多地方可以完善,但我們還是希望早點把部落格部署到伺服器上,讓他人可以通過外網訪問。至於有待完善的地方,可以等部署完後一點點地迭代和改進。現在就讓我們來把部落格部署到伺服器上吧!

注意:本文的每一個步驟都在真實環境下驗證無誤。除非你知道自己在做什麼,否則我們建議每一步均嚴格按照教程的指導來,這樣能保證你順利完成部署。

部署前準備

我們將使用比較流行的 Nginx + Gunicorn 的方式將 Django 開發的部落格部署到自己的伺服器,讓別人能夠通過域名訪問你的部落格。至於 Nginx、Gunicorn 是什麼暫時放到一邊,讀完本教程後你就會知道它們的作用和使用方法了。

為了部署我們的部落格,需要滿足以下兩個條件:

  1. 有一臺可以通過外網訪問的伺服器。
  2. 有一個域名。

如果你已經滿足以上條件,可以直接跳到後面的搭建伺服器部分。這裡簡單介紹一下我目前所知的以最低成本滿足以上兩個條件的方式。

購買伺服器

如果你是學生,推薦購買阿里雲伺服器,學生優惠價是 9.9 元/月,而且伺服器效能比較高。購買地址:阿里雲伺服器學生專區。具體的購買步驟這裡就不贅述了,根據網站的指引相信你肯定能夠購買成功。只是注意一點的是在選伺服器型別的時候選擇公共映象,這樣系統比較純淨。作業系統建議選 ubuntu 14.04 64位,這是本教程使用的伺服器環境。

如果你不是學生,推薦購買搬瓦工 vps。目前最便宜的是 19.9美元/年,缺點是伺服器效能沒有阿里雲高,但優點是順帶可以用它來搭梯子,從此訪問 google、youtube 不是夢(基於 shadowsocks 只需簡單幾步就可以搭建起自己的梯子伺服器)。同樣購買的過程就不贅述了,搬瓦工 vps 中文網 有超級詳細的指引。只是注意安裝作業系統時建議選 ubuntu 14.04 64位,這是本教程使用的伺服器環境。

如果你不差那點錢,隨意選擇一個雲伺服器提供商購買一個雲伺服器即可。

購買域名

域名服務商很多,我這裡使用的是 阿里雲域名註冊系統。域名是網站的門牌,如果打算長期運營這個網站建議多考慮考慮,選一個適當的域名。如果只是為了測試,隨便註冊一個域名即可,一些非常見字尾的域名非常便宜,一般 10元/年就能搞定。但注意一點根據工信部規定,以下字尾的域名需要實名認證後才能使用:

.cn/.com/.net/.top/.xyz/.vip/.club/.ren/.wang/.shop/.xin/.中國/.資訊/.公司/.網路/.廣東/.佛山

如果你購買的是上述字尾的域名,意味著需要提交個人的身份資料實名認證後才能正常使用,這通常需要花費幾天的時間。所以如果只為了測試和學習部署的話,最好避開上述字尾的域名。

搭建伺服器

本教程使用的本地環境為 Windows 10,伺服器環境為 ubuntu 14.04(64 位)。如果你的環境和我的有所差異導致一些命令無法執行,將這些命令轉換為你所在環境的命令執行即可。

遠端登入到伺服器

伺服器通常位於雲端,需要使用遠端登入工具登入後才能對伺服器進行操作。我使用的是 Xshell,Windows 下百度 Xshell 下載安裝即可,軟體對學校和個人使用者是免費的。

如何遠端登入到伺服器這裡就不贅述了,相信你參考網上的一些教程肯定能夠順利登入。假如你和我一樣使用 Xshell 的話,這裡有一篇很詳細的教程可以參考:教你怎麼使用xshell遠端連線linux伺服器

安裝軟體

順利連線到遠端伺服器了。如果是一臺全新伺服器的話,通常我們是以 root 使用者登入的。在 root 下部署程式碼不安全,最好是建一個新使用者(如果你已經以非 root 使用者登入的話可以跳過這一步)。下面的一些列命令將建立一個擁有超級許可權的新使用者:

# 在 root 使用者下執行這條命令建立一個新使用者,yangxg 是使用者名稱
# 因為我叫楊學光,所以我取的使用者名稱是 yangxg
# 選擇一個你喜歡的使用者名稱,不一定非得和我的相同
root@localhost:~# useradd -m -s /bin/bash yangxg

# 把新建立的使用者加入超級許可權組
root@localhost:~# usermod -a -G sudo yangxg

# 為新使用者設定密碼
# 注意在輸密碼的時候不會有字元顯示,不要以為鍵盤壞了,正常輸入即可
root@localhost:~# passwd yangxg

# 切換到建立的新使用者
root@localhost:~# su - yangxg

# 切換成功,@符號前面已經是新使用者名稱而不是 root 了
yangxg@localhost:~$複製程式碼

新使用者建立並切換成功了。如果是新伺服器的話,最好先更新一下系統,避免因為版本太舊而給後面安裝軟體帶來麻煩。執行下面的兩條命令:

yangxg@localhost:~$ sudo apt-get update
yangxg@localhost:~$ sudo apt-get upgrade複製程式碼

接下來就可以安裝必要的軟體了,這裡我們需要用到的軟體有 Nginx、Pytohn3、Git、pip 和 virtualenv。

yangxg@localhost:~$ sudo apt-get install nginx
yangxg@localhost:~$ sudo apt-get install git python3 python3-pip
yangxg@localhost:~$ sudo pip3 install virtualenv複製程式碼

解析域名到伺服器的 IP 地址

將域名和伺服器的 IP 地址繫結後,使用者就可以通過在瀏覽器輸入域名來訪問伺服器了。

各大域名服務商都提供了域名解析服務,但其配置介面各有差異,請依據其指引完成域名解析。下面是我使用的阿里雲域名解析頁面。

14 - 使用 Nginx 和 Gunicorn 部署 Django 部落格
阿里雲域名解析設定介面

啟動 Nginx 服務

Nginx 是用來處理靜態檔案請求的。比如當我們訪問一個部落格文章詳情頁面時,伺服器會接收到下面兩種請求:

  • 顯示文章的詳情資訊,這些資訊通常儲存在資料庫裡,因此需要呼叫資料庫獲取資料。
  • 圖片、css、js 等存在伺服器某個資料夾下的靜態檔案。

對於前一種請求,部落格文章的資料需要藉助 Django 從資料庫中獲取,Nginx 處理不了,它就會把這個請求轉發給 Django,讓 Django 去處理。而對於後一種靜態檔案的請求,只需要去這些靜態檔案所在的資料夾獲取,Nginx 就會代為處理,不再麻煩 Django。

用 Django 去獲取靜態檔案是很耗時的,但 Nginx 可以很高效地處理,這就是我們要使用 Nginx 的原因(當然其功能遠不止這些)。

通過前面的步驟我們已經安裝了 Nginx,並且已經把域名和伺服器 IP 繫結了。執行下面的命令啟動 Nginx 服務:

yangxg@localhost:~$ sudo service nginx start複製程式碼

在瀏覽器輸入域名,看到如下頁面說明 Nginx 啟動成功了。

14 - 使用 Nginx 和 Gunicorn 部署 Django 部落格
Nginx歡迎頁面

部署程式碼

部署前的專案配置

Django 專案中會有一些 CSS、JavaScript 等靜態檔案,為了能夠方便地讓 Nginx 處理這些靜態檔案的請求,我們把專案中的全部靜態檔案收集到一個統一的目錄下,這個目錄通常位於 Django 專案的根目錄,並且命名為 static。為了完成這些任務,需要在專案的配置檔案裡做一些必要的配置:

blogproject/settings.py

# 其他配置...

STATIC_URL = '/static/'
# 加入下面的配置
STATIC_ROOT = os.path.join(BASE_DIR, 'static')複製程式碼

STATIC_ROOT 指明瞭靜態檔案的收集目錄,即專案根目錄(BASE_DIR)下的 static 資料夾。

為了安全起見,在生產環境下需要關閉 DEBUG 選項以及設定允許訪問的域名。開啟 settings.py 檔案,找到 DEBUGALLOWED_HOSTS 這兩個選項,將它們設定成如下的值:

blogproject/settings.py

DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1', 'localhost ', '.zmrenwu.com']複製程式碼

ALLOWED_HOSTS 是允許訪問的域名列表,127.0.0.1 和 localhost 是本地訪問的域名,.zmrenwu.com 是訪問伺服器的域名(換成你自己的域名)。域名前加一個點表示允許訪問該域名下的子域名,比如 www.zmrenwu.com、test.zmrenwu.com 等二級域名同樣允許訪問。如果不加前面的點則只允許訪問 zmrenwu.com。

專案還會依賴一些第三方 Python 庫,為了方便在伺服器上一次性安裝,我們將全部依賴寫入一個叫 requirements.txt 的文字檔案中。啟用本地的虛擬環境(如果你使用了虛擬環境的話),並進入專案的根目錄,執行 pip freeze > requirements.txt 命令:

(blogproject_env) C:\Users\yangxg\Workspace\blogproject>
pip freeze > requirements.txt複製程式碼

這時專案根目錄下會生成了一個 requirements.txt 的文字檔案,其內容記錄了專案的全部依賴。

將程式碼上傳到 GitHub

將程式碼上傳到 GitHub 等程式碼託管平臺,這樣我們就可以方便地把程式碼拉取到伺服器了。Git 和 GitHub 的使用相信你已經很熟悉了,這裡就不贅述過程。如果不知道如何使用地話可以自行百度相關教程。

注意資料庫檔案不要上傳!

設定伺服器目錄結構

接下來需要把程式碼上傳到伺服器了。我伺服器上存放程式碼的目錄結構一般是這樣的:

/home/yangxg/
    sites/
        demo.zmrenwu.com/
            env/
            django-blog-tutorial/複製程式碼

一臺伺服器可能部署多個網站,所有網站程式碼都放在 sites/ 目錄下。demo.zmrenwu.com/ 這個資料夾以網站的域名命名,便於區分。env/ 是 python 虛擬環境目錄。django-blog-tutorial/ 是 Django 部落格專案目錄。

因此先來建立這個目錄結構,注意目錄名替換為你自己的域名,以後涉及到 demo.zmrenwu.com 的地方通常都要替換你自己的域名,後面就不再一一指出了,執行下面的命令,

yangxg@localhost:~$ mkdir -p ~/sites/demo.zmrenwu.com複製程式碼

這裡 ~ 代表當前使用者的 home 目錄,即 /home/yangxg/。

接下來建立虛擬環境,先進入到 demo.zmrenwu.com 目錄下,然後執行 virtualenv 命令建立虛擬環境:

yangxg@localhost:~$ cd ~/sites/demo.zmrenwu.com
yangxg@localhost:~/sites/demo.zmrenwu.com$ virtualenv --python=python3 env複製程式碼

注意這裡使用 --python=python3 來指定克隆 Python3 的環境。因為 ubuntu 系統預設安裝了 Python2,如果不特別指定的話 Virtualenv 預設克隆的是 Python2 的環境。

檢查一下虛擬環境是否建立成功,執行 ls 命令列出當前目錄下的檔案和資料夾,看到 env 這個資料夾說明虛擬環境建立成功。

yangxg@localhost:~/sites/demo.zmrenwu.com$ ls
env複製程式碼

接著再從程式碼倉庫把專案程式碼拉取過來,把 git clone 後的地址換成你自己的 GitHub 倉庫地址!

yangxg@localhost:~/sites/demo.zmrenwu.com$ git clone https://github.com/zmrenwu/django-blog-tutorial.git複製程式碼

執行 ls 命令檢查一下是否拉取成功:

yangxg@localhost:~/sites/demo.zmrenwu.com$ ls
django-blog-tutorial  env複製程式碼

多了 django-blog-tutorial 資料夾(資料夾名稱由你的 GitHub 倉庫名決定),說明拉取成功了。

安裝專案依賴

啟用虛擬環境,再進入到專案根目錄,即 requirements.txt 所在的目錄,安裝專案的全部依賴:

yangxg@localhost:~/sites/demo.zmrenwu.com$ source env/bin/activate
(env) yangxg@localhost:~/sites/demo.zmrenwu.com$ cd django-blog-tutorial/
(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install -r requirements.txt複製程式碼

收集靜態檔案

虛擬環境下繼續執行 python manage.py collectstatic 命令收集靜態檔案到 static 目錄下:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py collectstatic複製程式碼

生成資料庫

虛擬環境下繼續執行 python manage.py migrate 命令建立資料庫檔案:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py migrate複製程式碼

建立超級使用者

虛擬環境下繼續執行 python manage.py createsuperuser 命令建立一個超級使用者,方便我們進入 Django 管理後臺。這和本地開發時是一樣的,具體請參照:在 Django Admin 後臺文章

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ python manage.py createsuperuser複製程式碼

配置 Nginx

接下是配置 Nginx 來處理使用者請求。

先在伺服器的 /etc/nginx/sites-available/ 目錄下新建一個配置檔案,檔名我一般就設定為域名。寫上下面的配置內容:

/etc/nginx/sites-available/demo.zmrenwu.com

server {
    charset utf-8;
    listen 80;
    server_name demo.zmrenwu.com; ①

    location /static { ②
        alias /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial/static; 
    }

    location / { ③
        proxy_set_header Host $host;
        proxy_pass http://unix:/tmp/demo.zmrenwu.com.socket;
    }
}複製程式碼

① 服務的域名為 demo.zmrenwu.com。

② 所有URL 帶有 /static 的請求均由 Nginx 處理,alias 指明瞭靜態檔案的存放目錄。

③ 其它請求轉發給 Django 處理。proxy_pass 後面使用了 unix 套接字,其作用是防止埠衝突,這裡就不再詳述。

至於怎麼在伺服器新建檔案和寫檔案,請自行學習一點點 vi 編輯器的用法,這裡也不一一講解了。

我們在 /etc/nginx/sites-available/ 放置了配置檔案,接下來需要建立一個符號連結,把這個配置檔案加入到啟用的網站列表中去,被啟用網站的目錄在 /etc/nginx/sites-enabled/,你可以理解為從 sites-available/ 目錄下傳送了一個配置檔案的快捷方式到 sites-enabled/ 目錄。具體命令如下:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ sudo ln -s /etc/nginx/sites-available/demo.zmrenwu.com /etc/nginx/sites-enabled/demo.zmrenwu.com複製程式碼

使用 Gunicorn

Gunicorn 一般用來管理多個程式,有程式掛了Gunicorn 可以把它拉起來,防止伺服器長時間停止服務,還可以動態調整 worker 的數量,請求多的時候增加 worker 的數量,請求少的時候減少。

在虛擬環境下,安裝 Gunicorn:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ pip install gunicorn複製程式碼

用 Gunicorn 啟動伺服器程式:

(env) yangxg@localhost:~/sites/demo.zmrenwu.com/django-blog-tutorial$ gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application複製程式碼

瀏覽器輸入域名,可以看到訪問成功了!

自動啟動 Gunicorn

現在 Gunicorn 是我們手工啟動的,萬一哪天伺服器崩潰重啟了又得重新手工啟動。為此我們寫一個自動啟動指令碼,這樣當伺服器重新啟動後,指令碼會幫我們重啟 Gunicorn。先按 Ctrl + c 停止剛才啟動的伺服器程式。

寫一個啟動指令碼,這樣當伺服器重啟後能自動引導 Gunicorn 的啟動。指令碼位於 /etc/init/ 目錄下,且指令碼檔名必須以 .conf 結尾:

/etc/init/gunicorn-demo.zmrenwu.com.conf

start on net-device-up ①
stop on shutdown

respawn ②

setuid yangxg ③
chdir /home/yangxg/sites/demo.zmrenwu.com/django-blog-tutorial ④

exec ../env/bin/gunicorn --bind unix:/tmp/demo.zmrenwu.com.socket blogproject.wsgi:application ⑤複製程式碼

① start on net-device-up 確保只在伺服器聯網時才啟動 Gunicorn。

② 如果程式崩潰了(比如伺服器重啟或者程式因為某些以外情況被 kill),respawn 將自動重啟 Gunicorn。

③ setuid 確保以 yangxg 使用者的身份(換成你自己的使用者名稱)執行 Gunicorn 程式。

④ chdir 進入到指定目錄,這裡進入專案的根目錄。

⑤ exec 執行程式,即開啟伺服器程式。

現在可以用 start 命令啟動 Gunicorn 了:

sudo start gunicorn-demo.zmrenwu.com複製程式碼

以後如果更新了程式碼,只要執行下面的命令重啟一下 Nginx 和 Gunicorn 就可以使新的程式碼生效了:

sudo service nginx reload
sudo restart gunicorn-demo.zmrenwu.com複製程式碼

使用 CDN 加快 Bootstrap 和 jQuery 的載入速度

我們的專案使用了 Bootstrap 和 jQuery,這兩個檔案我們是從本地載入的。如果伺服器效能比較差的話,載入需要耗費很長的時間,網站開啟的速度就變得無法忍受。我們使用 CDN 來加快載入速度。具體來說,替換 base.html 的幾個靜態檔案的載入標籤:

base.html

- <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
- <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
- <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
+ <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+ <script src="https://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
+ <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>複製程式碼

這樣網站訪問的速度將大大提升!

部署過程自動化

在整個部署過程中我們執行了十幾條命令,手動輸入了 N 個字元。如果每次更新程式碼都要遠端連線到伺服器執行這些命令的話將變得非常麻煩。接下來的教程我們將介紹使用 Fabric 自動化整個部署過程。寫好部署指令碼後,只需要執行一條命令,就可以非常方便地自動完成整個部署。

總結

本章節的程式碼位於:Step14: deploy using nginx and gunicorn

如果遇到問題,請通過下面的方式尋求幫助。

更多Django 教程,請訪問 追夢人物的部落格

相關文章