Django初學(xué)者入門(mén)指南7-部署發(fā)布(譯&改)

Django初學(xué)者入門(mén)指南1-初識(shí)(譯&改)

Django初學(xué)者入門(mén)指南2-基礎(chǔ)知識(shí)(譯&改)

Django初學(xué)者入門(mén)指南3-高級(jí)概念(譯&改)

Django初學(xué)者入門(mén)指南4-登錄認(rèn)證(譯&改)

Django初學(xué)者入門(mén)指南5-存儲(chǔ)數(shù)據(jù)(譯&改)

Django初學(xué)者入門(mén)指南6-基于類(lèi)的頁(yè)面(譯&改)

Django初學(xué)者入門(mén)指南7-部署發(fā)布(譯&改)

>>原文地址 By Vitor Freitas

image

簡(jiǎn)介

歡迎來(lái)到DJango入門(mén)教程系列的最后一部分痘拆!在本教程中嚷硫,我們將把DJango應(yīng)用程序部署到生產(chǎn)服務(wù)器上橱赠。同時(shí)還將為我們的服務(wù)器配置電子郵件服務(wù)和HTTPS證書(shū)责嚷。

最開(kāi)始我想給出一個(gè)使用虛擬專(zhuān)用服務(wù)器(VPS)的示例,它的應(yīng)用更加廣泛一點(diǎn)郭蕉。然后使用一個(gè)平臺(tái)服務(wù)泥畅,比如Heroku代承,但是它有太多細(xì)節(jié)需要處理龟梦。所以最終我選擇做一個(gè)主要使用VPS的教程隐锭。

我們的項(xiàng)目已經(jīng)上線啦!如果想在閱讀本教程之前在線體驗(yàn)一下计贰,可以直接訪問(wèn)我部署的網(wǎng)站:www.djangoboards.com钦睡。


代碼版本管理工具

版本控制是軟件開(kāi)發(fā)中一個(gè)極其重要的課題,尤其是在與團(tuán)隊(duì)一起工作并同時(shí)維護(hù)生產(chǎn)代碼躁倒、多個(gè)功能并行開(kāi)發(fā)時(shí)荞怒。無(wú)論是一個(gè)開(kāi)發(fā)人員項(xiàng)目還是多個(gè)開(kāi)發(fā)人員項(xiàng)目,每個(gè)項(xiàng)目都應(yīng)該進(jìn)行版本控制秧秉。

代碼版本管理工具有許多選擇褐桌,也許是因?yàn)?strong>GitHub的流行,Git在版本控制中成為了佼佼者象迎。因此荧嵌,如果你不熟悉版本控制,用Git就是一個(gè)很好的選擇砾淌。Git有許多教程啦撮、課程和資源,很容易找到需要的資料汪厨。

GitHubCode School有一個(gè)關(guān)于Git的很好的交互式教程逻族,我在幾年前開(kāi)始從SVN轉(zhuǎn)到Git時(shí)就學(xué)習(xí)過(guò)這個(gè)教程,它做得很棒骄崩。

這是一個(gè)非常重要的注意事項(xiàng)聘鳞,本該從第一個(gè)教程開(kāi)始就強(qiáng)調(diào)它,不過(guò)因?yàn)楸鞠盗薪坛痰闹攸c(diǎn)是Django要拂,所以還是到這里才開(kāi)始講抠璃。如果這一切對(duì)你來(lái)說(shuō)都是陌生的,別擔(dān)心脱惰。一步一步來(lái)搏嗡。第一個(gè)項(xiàng)目不會(huì)是完美的,不斷學(xué)習(xí)和發(fā)展你的技能才是更重要的拉一,要持之以恒采盒。

Git它不僅僅是一個(gè)版本控制系統(tǒng),還有一個(gè)圍繞它構(gòu)建的工具和服務(wù)的豐富生態(tài)系統(tǒng)蔚润。比如說(shuō)持續(xù)集成磅氨、部署、代碼評(píng)審嫡纠、代碼質(zhì)量和項(xiàng)目管理等烦租。

使用Git支持Django項(xiàng)目的部署過(guò)程非常高效延赌。從源代碼庫(kù)中提取最新版本或在出現(xiàn)問(wèn)題時(shí)回滾到特定版本的都非常簡(jiǎn)單。還有許多服務(wù)與Git集成以便執(zhí)行自動(dòng)化測(cè)試和部署叉橱。

如果你的還沒(méi)有安裝Git挫以,請(qǐng)?jiān)谶@里下載https://git-scm.com/downloads

配置Git

首先配置你的身份:

git config --global user.name "Vitor Freitas"
git config --global user.email vitor@simpleisbetterthancomplex.com

找到項(xiàng)目根目錄(manage.py所在的目錄)窃祝,初始化一個(gè)Git本地倉(cāng)庫(kù):

git init
Initialized empty Git repository in /Users/vitorfs/Development/myproject/.git/

檢查一下代碼倉(cāng)庫(kù)的狀態(tài):

git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

  accounts/
  boards/
  manage.py
  myproject/
  requirements.txt
  static/
  templates/

nothing added to commit but untracked files present (use "git add" to track)

在繼續(xù)添加源代碼文件之前掐松,請(qǐng)?jiān)陧?xiàng)目根目錄中創(chuàng)建一個(gè).gitignore的新文件,這個(gè)新文件將幫助我們過(guò)濾代碼倉(cāng)庫(kù)管理的文件粪小,忽略諸如緩存文件甩栈、日志文件等不需要進(jìn)行管理的非必要文件。

你可以從GitHub上獲取Python項(xiàng)目的常用.gitignore文件糕再,這里

確認(rèn)文件的名稱(chēng)一定要是.gitignore玉转,而不是Python.gitignore之類(lèi)的突想。

舉個(gè)例子,你可以在.gitignore里添加對(duì)SQLite數(shù)據(jù)庫(kù)文件的過(guò)濾:

  • .gitignore
__pycache__/
*.py[cod]
.env
venv/

# SQLite database files

*.sqlite3

好了究抓,現(xiàn)在我們將項(xiàng)目的文件添加到Git本地倉(cāng)庫(kù):

git add .

注意這里的.猾担,這個(gè)命令的意思是將這個(gè)目錄下的所有未添加到Git倉(cāng)庫(kù)里的文件(不包括被.gitignore忽略的文件),添加到倉(cāng)庫(kù)里刺下。

然后提交一次代碼:

git commit -m "Initial commit"

養(yǎng)成一個(gè)好習(xí)慣绑嘹,每次提交的時(shí)候都添加備注,簡(jiǎn)要說(shuō)明這次提交的內(nèi)容橘茉。

遠(yuǎn)程倉(cāng)庫(kù)

現(xiàn)在讓我們使用GitHub來(lái)配置這個(gè)項(xiàng)目的一個(gè)遠(yuǎn)程倉(cāng)庫(kù)把工腋。第一步,在GitHub上創(chuàng)建一個(gè)賬號(hào)畅卓,確認(rèn)你的郵件地址擅腰。然后你就可以創(chuàng)建GitHub倉(cāng)庫(kù)了。

然后我們需要為倉(cāng)庫(kù)命名翁潘,其他的選項(xiàng)(README、.gitignore拜马、license)都暫時(shí)不要勾選或添加渗勘,確保項(xiàng)目是一個(gè)空項(xiàng)目:

GitHub

在你建好項(xiàng)目后應(yīng)該看見(jiàn)下面的頁(yè)面:

GitHub

在本地開(kāi)始配置吧,運(yùn)行下面的命令:

git remote add origin git@github.com:sibtc/django-boards.git

執(zhí)行push命令把本地代碼推到遠(yuǎn)程倉(cāng)庫(kù):

git push origin master

Counting objects: 84, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (81/81), done.
Writing objects: 100% (84/84), 319.70 KiB | 0 bytes/s, done.
Total 84 (delta 10), reused 0 (delta 0)
remote: Resolving deltas: 100% (10/10), done.
To git@github.com:sibtc/django-boards.git
 * [new branch]      master -> master
GitHub

這里創(chuàng)建的代碼倉(cāng)庫(kù)只是為了演示如何給現(xiàn)有的項(xiàng)目添加Git代碼倉(cāng)庫(kù)以及添加遠(yuǎn)程倉(cāng)庫(kù)俩莽,實(shí)際上這個(gè)項(xiàng)目的官方遠(yuǎn)程倉(cāng)庫(kù)是:https://github.com/sibtc/django-beginners-guide.


項(xiàng)目配置

不管代碼是保存在一個(gè)公開(kāi)或私有的遠(yuǎn)程倉(cāng)庫(kù)旺坠,那些敏感信息都不應(yīng)該被提交到遠(yuǎn)程倉(cāng)庫(kù)里,例如密鑰扮超、密碼价淌、API密鑰等申眼。

基于這個(gè)原則,我們需要對(duì)settings.py里特定的兩類(lèi)信息進(jìn)行處理:

  • 諸如密碼蝉衣、秘鑰之類(lèi)的敏感信息括尸;
  • 特定環(huán)境使用的配置信息.

密碼和密鑰可以使用本地文件或環(huán)境變量進(jìn)行存儲(chǔ),不要提交到遠(yuǎn)程倉(cāng)庫(kù):

# 環(huán)境變量
import os
SECRET_KEY = os.environ['SECRET_KEY']

# 或本地文件
with open('/etc/secret_key.txt') as f:
    SECRET_KEY = f.read().strip()

這里推薦一個(gè)強(qiáng)大的工具庫(kù)Python Decouple病毡,我每一個(gè)DJango項(xiàng)目開(kāi)發(fā)中都會(huì)用它濒翻。它可以自動(dòng)檢索名為.env本地文件來(lái)關(guān)聯(lián)配置的變量,進(jìn)行設(shè)置和讀取啦膜。同時(shí)它也提供接口來(lái)定義默認(rèn)值有送,并在可能的條件下將數(shù)據(jù)轉(zhuǎn)換為intboollist等類(lèi)型僧家。

這個(gè)不是必須的雀摘,但是我強(qiáng)烈建議使用它。

執(zhí)行下面的命令安裝一下:

pip install python-decouple
  • myproject/settings.py
from decouple import config

SECRET_KEY = config('SECRET_KEY')

然后把敏感信息抽取出來(lái)八拱,放到項(xiàng)目根目錄與manage.py同級(jí)的一個(gè)新文件.env里阵赠,注意這里也是以點(diǎn)開(kāi)頭的文件名:

myproject/
 |-- myproject/
 |    |-- accounts/
 |    |-- boards/
 |    |-- myproject/
 |    |-- static/
 |    |-- templates/
 |    |-- .env        <-- 這里!
 |    |-- .gitignore
 |    |-- db.sqlite3
 |    +-- manage.py
 +-- venv/
  • .env
SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d

.env.gitignore中已經(jīng)被配置為了忽略,所以每當(dāng)需要部署應(yīng)用程序或者在新的設(shè)備上運(yùn)行這個(gè)項(xiàng)目時(shí)肌稻,我們都需要新建一個(gè).env文件并添加必要的配置變量清蚀。

讓我們?cè)侔惭b一個(gè)三方庫(kù)來(lái)幫助我們進(jìn)行數(shù)據(jù)庫(kù)的配置。它讓我們可以通過(guò)一行文本就實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)連接的配置:

pip install dj-database-url

現(xiàn)在我們需要解耦所有的配置:

  • myproject/settings.py
from decouple import config, Csv
import dj_database_url

SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
DATABASES = {
    'default': dj_database_url.config(
        default=config('DATABASE_URL')
    )
}

下面是我們本地設(shè)備的一個(gè)示例配置文件.env

SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d
DEBUG=True
ALLOWED_HOSTS=.localhost,127.0.0.1

注意這里DEBUG配置項(xiàng)設(shè)了一個(gè)默認(rèn)值爹谭,當(dāng)部署到生產(chǎn)環(huán)境時(shí)枷邪,只需要忽略去配置這一項(xiàng)就可以了,它會(huì)默認(rèn)為False诺凡。

這里ALLOWED_HOSTS將會(huì)被轉(zhuǎn)換成一個(gè)類(lèi)似['.localhost', '127.0.0.1'. ]的列表东揣,這是本地設(shè)備的配置,如果是生產(chǎn)設(shè)備腹泌,它應(yīng)該是['.djangoboards.com', ]這樣的或者其他你所擁有的域名救斑。

這個(gè)配置可以保證你的應(yīng)用程序只在這個(gè)域名下提供服務(wù)。


項(xiàng)目依賴(lài)跟蹤

持續(xù)保持跟蹤項(xiàng)目的依賴(lài)配置是一個(gè)好習(xí)慣真屯,這樣可以更方便地將項(xiàng)目部署到其他設(shè)備上脸候。

我們可以通過(guò)下面的命令檢查現(xiàn)在安裝的依賴(lài)庫(kù):

pip freeze

dj-database-url==0.4.2
Django==1.11.6
django-widget-tweaks==1.4.1
Markdown==2.6.9
python-decouple==3.1
pytz==2017.2

創(chuàng)建一個(gè)名為requirements.txt的文件放到項(xiàng)目根目錄,將項(xiàng)目的依賴(lài)拷貝到這里:

  • requirements.txt
dj-database-url==0.4.2
Django==1.11.6
django-widget-tweaks==1.4.1
Markdown==2.6.9
python-decouple==3.1

這里剔除了pytz==2017.2绑蔫,因?yàn)檫@個(gè)是由DJango自動(dòng)安裝的运沦。

將文件添加到Git倉(cāng)庫(kù)并推送到遠(yuǎn)程倉(cāng)庫(kù):

git add .
git commit -m "Add requirements.txt file"
git push origin master

域名

需要申請(qǐng)一個(gè)域名來(lái)部署DJango應(yīng)用程序,這樣我們才能配置電子郵件服務(wù)和https證書(shū)配深。

這里我注冊(cè)了域名www.DjangoBoards.com携添。


部署策略

下面是本教程中將使用的部署策略的架構(gòu)設(shè)計(jì):

云服務(wù)是使用的Digital Ocean的VPS,這里根據(jù)大家實(shí)際情況自行注冊(cè)篓叶。

首先會(huì)有一個(gè)NGINX烈掠,插圖使用的是一個(gè)獸人羞秤。NGINX會(huì)首先接收到所有的請(qǐng)求,但它不會(huì)對(duì)這些請(qǐng)求數(shù)據(jù)做復(fù)雜的處理左敌。除非請(qǐng)求的數(shù)據(jù)是它自己能提供的服務(wù)如簡(jiǎn)單的獲取靜態(tài)資源瘾蛋,其他的請(qǐng)求它就直接傳遞給Gunicorn

NGINX還將配置HTTPS證書(shū)矫限,這樣就只接收HTTPS請(qǐng)求哺哼,如果客戶端嘗試通過(guò)HTTP訪問(wèn)服務(wù),NGINX可以重定位到HTTPS服務(wù)叼风,然后再對(duì)請(qǐng)求進(jìn)行處理取董。

我們也會(huì)安裝一個(gè)certbot來(lái)自動(dòng)更新Let’s Encrypt的證書(shū)。

Gunicorn是一個(gè)應(yīng)用服務(wù)器无宿,根據(jù)服務(wù)器的處理能力(處理器數(shù)量)茵汰,它能生成多個(gè)worker提供并行處理多任務(wù)的能力,同時(shí)它還能管理工作負(fù)載孽鸡,和執(zhí)行Python以及DJango代碼蹂午。

DJango承擔(dān)著最多的工作,它需要訪問(wèn)數(shù)據(jù)庫(kù)(如PostgreSQL)和文件系統(tǒng)梭灿,大多數(shù)的工作都集中在頁(yè)面里,渲染模板冰悠,所有在我們之前教程里的工作堡妒。當(dāng)DJango處理完請(qǐng)求后,它會(huì)返回處理結(jié)果給Gunicorn溉卓,再傳遞給NGINX皮迟,最終再傳回用戶客戶端。

還需要安裝PostgreSQL桑寨,一個(gè)生產(chǎn)級(jí)別的數(shù)據(jù)庫(kù)系統(tǒng)伏尼,通過(guò)DJango的ORM系統(tǒng),我們可以很簡(jiǎn)單的進(jìn)行數(shù)據(jù)庫(kù)切換尉尾。

最后一步是安裝Supervisor爆阶,這是一個(gè)過(guò)程監(jiān)控系統(tǒng),它會(huì)全程監(jiān)控GunicornDjango來(lái)保證服務(wù)的正常運(yùn)行沙咏。如果服務(wù)器重啟了辨图,或者Gunicorn異常退出了,Supervisor都會(huì)將自動(dòng)重啟故障的服務(wù)肢藐。


部署VPS (Digital Ocean)

你可以使用任何其他服務(wù)提供的VPS故河,配置方式應(yīng)該是類(lèi)似的,這里我們的服務(wù)器使用Ubuntu 16.04操作系統(tǒng)吆豹。

首先讓我們創(chuàng)建一個(gè)新服務(wù)器(Digital Ocean里被稱(chēng)為Droplet)鱼的,選擇操作系統(tǒng)Ubuntu 16.04

Digital Ocean

選擇服務(wù)器配置理盆,這里最低配置就可以了:

Digital Ocean

輸入一個(gè)主機(jī)名,這里我輸入的是django-boards

Digital Ocean

如果你有SSH秘鑰凑阶,你可以直接添加到你的賬戶里猿规,這樣你就可以直接使用秘鑰進(jìn)行登錄。如果沒(méi)有就只能通過(guò)郵箱獲取登錄根密碼晌砾。

選擇一下服務(wù)器的IP地址:

Digital Ocean

在登錄進(jìn)這個(gè)服務(wù)器前坎拐,將我們的域名指向這個(gè)IP地址,因?yàn)镈NS配置需要一點(diǎn)時(shí)間养匈,所以我們可以同步進(jìn)行哼勇。

Namecheap

這里我們添加了兩個(gè)A records,一個(gè)指向域名djangoboards.com呕乎,另一個(gè)指向www.djangoboards.com积担,接下啦我們會(huì)用NGINX配置一個(gè)規(guī)范的URL。

好了猬仁,讓我們?cè)诮K端上登錄服務(wù)器吧:

ssh root@45.55.144.54
root@45.55.144.54's password:

登錄成功后你會(huì)看到下面的消息:

You are required to change your password immediately (root enforced)
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-93-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.

Last login: Sun Oct 15 18:39:21 2017 from 82.128.188.51
Changing password for root.
(current) UNIX password:

重新設(shè)置登錄密碼帝璧,然后開(kāi)始配置服務(wù)器吧。

sudo apt-get update
sudo apt-get -y upgrade

如果在升級(jí)中出現(xiàn)任何提示湿刽,選擇keep the local version currently installed的烁。

Python 3.6

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.6

PostgreSQL

sudo apt-get -y install postgresql postgresql-contrib

NGINX

sudo apt-get -y install nginx

Supervisor

sudo apt-get -y install supervisor

sudo systemctl enable supervisor
sudo systemctl start supervisor

Virtualenv

wget https://bootstrap.pypa.io/get-pip.py
sudo python3.6 get-pip.py
sudo pip3.6 install virtualenv
為應(yīng)用程序創(chuàng)建用戶

使用下面的命令創(chuàng)建新用戶:

adduser boards

一般來(lái)說(shuō),我會(huì)選擇使用應(yīng)用程序的名稱(chēng)诈闺,這樣可以將每個(gè)應(yīng)用程序的用戶權(quán)限獨(dú)立開(kāi)渴庆。

將這個(gè)新用戶添加到sudoers列表:

gpasswd -a boards sudo
PostgreSQL 數(shù)據(jù)庫(kù)配置

首先切換到postgres用戶:

sudo su - postgres

創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)用戶:

createuser u_boards

創(chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)文件并將這個(gè)用戶設(shè)為owner

createdb django_boards --owner u_boards

為用戶定義一個(gè)安全的密碼:

psql -c "ALTER USER u_boards WITH PASSWORD 'BcAZoYWsJbvE7RMgBPzxOCexPRVAq'"

退出postgres用戶:

exit
DJango項(xiàng)目配置

切換到應(yīng)用程序用戶:

sudo su - boards

首先我們看看當(dāng)前目錄:

pwd
/home/boards

首先將項(xiàng)目代碼從遠(yuǎn)程倉(cāng)庫(kù)clone下來(lái):

git clone https://github.com/sibtc/django-beginners-guide.git

創(chuàng)建一個(gè)虛擬環(huán)境:

virtualenv venv -p python3.6

初始化并啟用虛擬環(huán)境:

source venv/bin/activate

安裝依賴(lài):

pip install -r django-beginners-guide/requirements.txt

這里需要安裝兩個(gè)額外的庫(kù):GunicornPostgreSQL驅(qū)動(dòng):

pip install gunicorn
pip install psycopg2

/home/boards/django-beginners-guide目錄下,創(chuàng)建一個(gè).env文件來(lái)存儲(chǔ)數(shù)據(jù)庫(kù)的秘鑰雅镊、證書(shū)和其他配置:

  • /home/boards/django-beginners-guide/.env
SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d
ALLOWED_HOSTS=.djangoboards.com
DATABASE_URL=postgres://u_boards:BcAZoYWsJbvE7RMgBPzxOCexPRVAq@localhost:5432/django_boards

數(shù)據(jù)庫(kù)URL的語(yǔ)法是:postgres://db_user:db_password@db_host:db_port/db_name.

接下來(lái)讓我們遷移數(shù)據(jù)庫(kù)襟雷、處理靜態(tài)文件并創(chuàng)建一個(gè)超級(jí)用戶:

cd django-beginners-guide
python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, boards, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying boards.0001_initial... OK
  Applying boards.0002_auto_20170917_1618... OK
  Applying boards.0003_topic_views... OK
  Applying sessions.0001_initial... OK

再處理靜態(tài)文件:

python manage.py collectstatic

Copying '/home/boards/django-beginners-guide/static/js/jquery-3.2.1.min.js'
Copying '/home/boards/django-beginners-guide/static/js/popper.min.js'
Copying '/home/boards/django-beginners-guide/static/js/bootstrap.min.js'
Copying '/home/boards/django-beginners-guide/static/js/simplemde.min.js'
Copying '/home/boards/django-beginners-guide/static/css/app.css'
Copying '/home/boards/django-beginners-guide/static/css/bootstrap.min.css'
Copying '/home/boards/django-beginners-guide/static/css/accounts.css'
Copying '/home/boards/django-beginners-guide/static/css/simplemde.min.css'
Copying '/home/boards/django-beginners-guide/static/img/avatar.svg'
Copying '/home/boards/django-beginners-guide/static/img/shattered.png'
...

這個(gè)命令會(huì)將所有靜態(tài)文件拷貝到一個(gè)外部目錄讓NGINX為用戶提供服務(wù)。稍后會(huì)提到仁烹。

為應(yīng)用程序創(chuàng)建一個(gè)超級(jí)用戶:

python manage.py createsuperuser
Gunicorn配置

Gunicorn在代理服務(wù)器后面負(fù)責(zé)執(zhí)行DJango代碼耸弄。

/home/boards下創(chuàng)建一個(gè)新文件命名為gunicorn_start

#!/bin/bash

NAME="django_boards"
DIR=/home/boards/django-beginners-guide
USER=boards
GROUP=boards
WORKERS=3
BIND=unix:/home/boards/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=myproject.settings
DJANGO_WSGI_MODULE=myproject.wsgi
LOG_LEVEL=error

cd $DIR
source ../venv/bin/activate

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DIR:$PYTHONPATH

exec ../venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $WORKERS \
  --user=$USER \
  --group=$GROUP \
  --bind=$BIND \
  --log-level=$LOG_LEVEL \
  --log-file=-

這個(gè)腳本會(huì)啟動(dòng)應(yīng)用服務(wù)器,配置提供了諸如DJango項(xiàng)目所在位置卓缰、使用哪個(gè)應(yīng)用程序用戶啟動(dòng)服務(wù)器等信息口渔。

讓這個(gè)文件可以被運(yùn)行:

chmod u+x gunicorn_start

創(chuàng)建兩個(gè)空文件夾玉工,一個(gè)用來(lái)存儲(chǔ)socket文件,一個(gè)用來(lái)存儲(chǔ)日志文件:

mkdir run logs

現(xiàn)在我們的/home/boards目錄應(yīng)該是這個(gè)樣子的:

django-beginners-guide/
gunicorn_start
logs/
run/
staticfiles/
venv/

staticfiles是由collectstatic命令創(chuàng)建的。

配置Supervisor

首先在/home/boards/logs/下創(chuàng)建一個(gè)空的log文件:

touch logs/gunicorn.log

創(chuàng)建一個(gè)新的supervisor文件:

sudo vim /etc/supervisor/conf.d/boards.conf
[program:boards]
command=/home/boards/gunicorn_start
user=boards
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/home/boards/logs/gunicorn.log

保存文件并運(yùn)行下面的命令:

sudo supervisorctl reread
sudo supervisorctl update

檢查一下現(xiàn)在的狀態(tài):

sudo supervisorctl status boards
boards                           RUNNING   pid 308, uptime 0:00:07
配置 NGINX

下一步是配置NGINX服務(wù)器知举,關(guān)聯(lián)靜態(tài)文件至朗,和將請(qǐng)求傳遞給Gunicorn

/etc/nginx/sites-available/目錄下添加一個(gè)新的配置文件命名為boards

upstream app_server {
    server unix:/home/boards/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    server_name www.djangoboards.com;  # here can also be the IP address of the server

    keepalive_timeout 5;
    client_max_body_size 4G;

    access_log /home/boards/logs/nginx-access.log;
    error_log /home/boards/logs/nginx-error.log;

    location /static/ {
        alias /home/boards/staticfiles/;
    }

    # checks for static file, if not found proxy to app
    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
}

創(chuàng)建一個(gè)符號(hào)鏈接(symbolic link)到sites-enabled文件夾:

sudo ln -s /etc/nginx/sites-available/boards /etc/nginx/sites-enabled/boards

移除默認(rèn)的NGINX網(wǎng)站:

sudo rm /etc/nginx/sites-enabled/default

重啟NGINX服務(wù):

sudo service nginx restart

如果此時(shí)DNS配置已經(jīng)更新孕讳,那么www.djangoboards.com應(yīng)該已經(jīng)可以訪問(wèn)了奇徒。


配置電子郵件服務(wù)

最開(kāi)始建議使用Mailgun,它提供可靠的免費(fèi)服務(wù)計(jì)劃偿乖,每月可發(fā)送12,000次击罪。

注冊(cè)一個(gè)免費(fèi)賬號(hào)哲嘲,按照步驟填寫(xiě)信息就可以了,非常簡(jiǎn)單媳禁。這個(gè)需要和你的域名同時(shí)使用眠副,這個(gè)教程里就是Namecheap

點(diǎn)擊添加域名按鈕添加一個(gè)新的域名竣稽,根據(jù)提示進(jìn)行操作囱怕,需要保證使用"mg."的子域名:

Mailgun

從下圖的位置獲取DNS的記錄:

Mailgun

使用服務(wù)商提供的web頁(yè)面,將它添加到你的域名下毫别。
Add it to your domain, using the web interface offered by your registrar:

Namecheap

對(duì)MX也做童謠的操作:

Mailgun

將它們也添加到你的域名下:

Namecheap

這一步不是強(qiáng)制的娃弓,既然我們已經(jīng)到這里了,就也把它確認(rèn)一下吧:

Mailgun
Namecheap

在我們添加完DNS記錄后岛宦,點(diǎn)擊Check DNS Records Now

Mailgun

這里需要一點(diǎn)耐心台丛,可能需要多花一點(diǎn)時(shí)間來(lái)驗(yàn)證DNS配置是否生效。

我們可以先配置應(yīng)用程序接收的連接參數(shù)砾肺。

  • myproject/settings.py
EMAIL_BACKEND = config('EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend')
EMAIL_HOST = config('EMAIL_HOST', default='')
EMAIL_PORT = config('EMAIL_PORT', default=587, cast=int)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', default='')
EMAIL_USE_TLS = config('EMAIL_USE_TLS', default=True, cast=bool)

DEFAULT_FROM_EMAIL = 'Django Boards <noreply@djangoboards.com>'
EMAIL_SUBJECT_PREFIX = '[Django Boards] '

本地設(shè)備的.env文件應(yīng)該是下面這樣:

SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d
DEBUG=True
ALLOWED_HOSTS=.localhost,127.0.0.1
DATABASE_URL=sqlite:///db.sqlite3
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend

而生產(chǎn)環(huán)境的.env文件應(yīng)該是下面這樣:

SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d
ALLOWED_HOSTS=.djangoboards.com
DATABASE_URL=postgres://u_boards:BcAZoYWsJbvE7RMgBPzxOCexPRVAq@localhost:5432/django_boards
EMAIL_HOST=smtp.mailgun.org
EMAIL_HOST_USER=postmaster@mg.djangoboards.com
EMAIL_HOST_PASSWORD=ED2vmrnGTM1Rdwlhazyhxxcd0F

你可以在Mailgun上的Domain Information分段找到證書(shū)相關(guān)的信息挽霉。

  • EMAIL_HOST: SMTP 主機(jī)名
  • EMAIL_HOST_USER: 默認(rèn) SMTP 登錄賬戶
  • EMAIL_HOST_PASSWORD: 默認(rèn) 密碼

我們可以測(cè)試一下生產(chǎn)服務(wù)器的新配置。將本地設(shè)備的配置文件settings.py修改一下变汪,提交的遠(yuǎn)程倉(cāng)庫(kù)侠坎。再在服務(wù)器上拉取新代碼并重啟Gunicorn

git pull

編輯.env的電子郵件服務(wù)證書(shū)。

重啟Gunicorn

sudo supervisorctl restart boards

現(xiàn)在我們可以嘗試訪問(wèn)密碼重置流程:

密碼重置郵件

在Mailgun的dashboard上你可以查看一些郵件發(fā)送的統(tǒng)計(jì)信息:

Mailgun

配置 HTTPS 證書(shū)

現(xiàn)在讓我們給應(yīng)用程序配置一個(gè)HTTPS證書(shū)裙盾,這里選擇使用Let’s Encrypt实胸。

原來(lái)配置HTTPS沒(méi)有這么簡(jiǎn)單過(guò),甚至現(xiàn)在可以免費(fèi)使用它闷煤,他們提供了一個(gè)自動(dòng)安裝和刷新證書(shū)的解決方案certbot童芹,使用起來(lái)非常簡(jiǎn)單:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

現(xiàn)在安裝證書(shū):

sudo certbot --nginx

只需要跟著提示填寫(xiě)涮瞻,當(dāng)被問(wèn)到:

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.

選擇2就會(huì)將所有的HTTP請(qǐng)求重定位為HTTPS請(qǐng)求鲤拿。

這樣就可以保證所有請(qǐng)求都是通過(guò)HTTPS來(lái)進(jìn)行的:

HTTPS

修改配置為自動(dòng)更新證書(shū),執(zhí)行下面的命令來(lái)編輯crontab文件:

sudo crontab -e

在文件最后添加下面的這一行代碼:

0 4 * * * /usr/bin/certbot renew --quiet

這個(gè)命令會(huì)在每天的凌晨4點(diǎn)啟動(dòng)任務(wù)署咽,更新30天內(nèi)到期的證書(shū)近顷。


小結(jié)

非常感謝所有關(guān)注本系列教程的人給予的評(píng)論和反饋,我真的很感激宁否!這是本系列的最后一個(gè)教程窒升。希望你喜歡!

盡管這是本系列教程的最后一部分慕匠,但我計(jì)劃編寫(xiě)一些后續(xù)教程饱须,探索其他有趣的主題,例如數(shù)據(jù)庫(kù)優(yōu)化和在當(dāng)前已有的基礎(chǔ)上添加更多功能台谊。

順便說(shuō)一句蓉媳,如果你對(duì)這個(gè)項(xiàng)目感興趣譬挚,項(xiàng)目的源代碼可在GitHub上找到:https://github.com/sibtc/django-beginners-guide/

請(qǐng)告訴我你還想看到什么樣的教程!:-)

上一節(jié):Django初學(xué)者入門(mén)指南6-基于類(lèi)的頁(yè)面(譯&改)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酪呻,一起剝皮案震驚了整個(gè)濱河市减宣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌玩荠,老刑警劉巖漆腌,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異阶冈,居然都是意外死亡闷尿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)眼溶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悠砚,“玉大人,你說(shuō)我怎么就攤上這事堂飞」嗑桑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵绰筛,是天一觀的道長(zhǎng)枢泰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)铝噩,這世上最難降的妖魔是什么衡蚂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮骏庸,結(jié)果婚禮上毛甲,老公的妹妹穿的比我還像新娘。我一直安慰自己具被,他們只是感情好玻募,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著一姿,像睡著了一般七咧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叮叹,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天艾栋,我揣著相機(jī)與錄音,去河邊找鬼蛉顽。 笑死蝗砾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播悼粮,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拇泣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了矮锈?” 一聲冷哼從身側(cè)響起霉翔,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苞笨,沒(méi)想到半個(gè)月后债朵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瀑凝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年序芦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粤咪。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谚中,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寥枝,到底是詐尸還是另有隱情宪塔,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布囊拜,位于F島的核電站某筐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏冠跷。R本人自食惡果不足惜南誊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜜托。 院中可真熱鬧抄囚,春花似錦、人聲如沸橄务。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仪糖。三九已至柑司,卻和暖如春迫肖,著一層夾襖步出監(jiān)牢的瞬間锅劝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工蟆湖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留故爵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诬垂,于是被迫代替她去往敵國(guó)和親劲室。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355