歡迎來到咱們教程系列的最後一部分!在本教程中,咱們將把Django應用程序部署到生產服務器。咱們還將爲咱們的服務器配置電子郵件服務和HTTPS證書。css
首先,我想到了一個使用虛擬專用服務器(VPS)的例子,它更通用,而後使用一個平臺即服務,如Heroku。但它太詳細了,因此我最終建立了關於VPS的本教程。html
咱們的項目現場直播!若是您想在查看文本以前在線查看,這是咱們要部署的應用程序:www.djangoboards.com。python
版本控制是軟件開發中很是重要的主題。特別是在與團隊合做並同時維護生產代碼時,並行開發了多個功能。不管是一個開發人員項目仍是多個開發人員項目,每一個項目都應該使用版本控制。jquery
版本控制系統有幾種選擇。也許是由於GitHub的流行,Git 成爲版本控制的事實標準。因此若是你不熟悉版本控制,Git是一個很好的起點。通常有不少教程,課程和資源,所以很容易找到幫助。linux
GitHub和Code School有一個關於Git的很棒的互動教程,幾年前我開始從SVN轉到Git。這是一個很是好的介紹。nginx
這是一個很是重要的主題,我可能應該從第一個教程開始提出它。但事實是我但願本教程系列的重點放在Django上。若是這一切對您來講都是新的,請不要擔憂。一步一步是很重要的。你的第一個項目並不完美。重要的是要保持學習和慢慢發展你的技能,但要保持穩定。git
關於Git的一個很是好的事情是它不只僅是一個版本控制系統。圍繞它創建了豐富的工具和服務生態系統。一些很好的例子是持續集成,部署,代碼審查,代碼質量和項目管理。github
使用Git來支持Django項目的部署過程很是有效。這是從源代碼存儲庫中提取最新版本或在出現問題時回滾到特定版本的便捷方式。有許多服務與Git集成,以便自動化測試執行和部署。sql
若是您沒有在本地計算機上安裝Git,請從https://git-scm.com/downloads獲取已安裝的。數據庫
首先,設置你的身份:
git config --global user.name "Vitor Freitas" git config --global user.email vitor@simpleisbetterthancomplex.com
在項目根目錄(與manage.py相同的目錄)中,初始化一個git存儲庫:
git init
Initialized empty Git repository in /Users/vitorfs/Development/myproject/.git/
檢查存儲庫的狀態:
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)
在繼續添加源文件以前,請在項目根目錄中建立名爲.gitignore的新文件。這個特殊的文件將幫助咱們保持存儲庫的清潔,而不須要像緩存文件或日誌這樣的沒必要要的文件。
您能夠 從GitHub 獲取Python項目的通用.gitignore文件。
確保將它從Python.gitignore重命名爲.gitignore(點很重要!)。
您能夠補充.gitignore文件,告訴它忽略SQLite數據庫文件,例如:
的.gitignore
__pycache__/ *.py[cod] .env venv/ # SQLite database files *.sqlite3
如今將文件添加到存儲庫:
git add .
請注意這裏的點。上面的命令告訴Git 在當前目錄中添加全部未跟蹤的文件。
如今進行第一次提交:
git commit -m "Initial commit"
老是寫一個評論告訴這個提交是什麼,簡要描述你改變了什麼。
如今讓咱們將GitHub設置爲遠程存儲庫。首先,在GitHub上建立一個免費賬戶,而後確認您的電子郵件地址。以後,您將可以建立公共存儲庫。
如今,只需爲存儲庫選擇一個名稱,不要使用自述文件初始化它,或者添加.gitignore或添加許可證到目前爲止。確保將存儲庫空啓動:
建立存儲庫後,您應該看到以下內容:
如今讓咱們將其配置爲咱們的遠程存儲庫:
git remote add origin git@github.com:sibtc/django-boards.git
如今將代碼推送到遠程服務器,即GitHub存儲庫:
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
我建立此存儲庫只是爲了演示使用現有代碼庫建立遠程存儲庫的過程。該項目的源代碼正式託管在此存儲庫中:https: //github.com/sibtc/django-beginners-guide。
不管代碼是存儲在公共或私有遠程存儲庫中,都不應提交敏感信息並將其推送到遠程存儲庫。這包括密鑰,密碼,API密鑰等。
此時,咱們必須在settings.py模塊中處理兩種特定類型的配置:
密碼和密鑰能夠存儲在環境變量中或使用本地文件(未提交到遠程存儲庫):
# environment variables import os SECRET_KEY = os.environ['SECRET_KEY'] # or local files with open('/etc/secret_key.txt') as f: SECRET_KEY = f.read().strip()
爲此, 我在我開發的每一個Django項目中都使用了一個名爲Python Decouple的優秀實用程序庫。它將搜索名爲.env的本地文件以設置配置變量,並將回退到環境變量。它還提供了一個定義默認值的接口,在適用時將數據轉換爲int,bool和list。
這不是強制性的,但我真的以爲它是一個很是有用的工具。它像Heroku這樣的服務就像魅力同樣。
首先,讓咱們安裝它:
pip install python-decouple
的myproject / settings.py
from decouple import config SECRET_KEY = config('SECRET_KEY')
如今,咱們能夠將敏感信息放在一個名爲.env的特殊文件中(注意前面的點),該文件位於manage.py文件所在的目錄中:
myproject/ |-- myproject/ | |-- accounts/ | |-- boards/ | |-- myproject/ | |-- static/ | |-- templates/ | |-- .env <-- here! | |-- .gitignore | |-- db.sqlite3 | +-- manage.py +-- venv/
.ENV
SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d
該.ENV文件中忽略的.gitignore文件,因此每次咱們要部署應用程序或在不一樣的機器上運行時,咱們將建立一個.ENV文件,並添加必要的配置。
如今讓咱們安裝另外一個庫來幫助咱們在一行中編寫數據庫鏈接。這樣,在不一樣的環境中編寫不一樣的數據庫鏈接字符串會更容易:
pip install dj-database-url
目前,咱們須要解耦的全部配置:
的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') ) }
本地計算機的.env文件示例:
SECRET_KEY=rqr_cjv4igscyu8&&(0ce(=sy=f2)p=f_wn&@0xsp7m$@!kp=d DEBUG=True ALLOWED_HOSTS=.localhost,127.0.0.1
請注意,在DEBUG
配置中咱們有一個默認值,所以在生產中咱們能夠忽略此配置,由於它將被設置爲False
自動設置,由於它應該是。
如今ALLOWED_HOSTS
將被轉換成一個列表['.localhost', '127.0.0.1'. ]
。如今,這是在咱們的本地機器上,爲了生產,咱們將其設置爲相似於['.djangoboards.com', ]
您擁有的任何域。
此特定配置可確保您的應用程序僅提供給此域。
跟蹤項目的依賴關係是一個很好的作法,所以更容易在另外一臺機器上安裝它。
咱們能夠經過運行命令來檢查當前安裝的Python庫:
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
在項目根目錄中建立名爲requirements.txt的文件,並在其中添加依賴項:
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,由於它是由Django自動安裝的。
您能夠更新源代碼存儲庫:
git add . git commit -m "Add requirements.txt file" git push origin master
若是咱們要正確部署Django應用程序,咱們將須要一個域名。擁有域名來爲應用程序提供服務,配置電子郵件服務和配置https證書很是重要。
最近,我一直在使用Namecheap 。您能夠以8.88美圓/年的價格得到.com域名,或者若是您只是嘗試一下,您能夠 以0.99美圓/年的價格註冊.xyz域名。
不管如何,您能夠自由使用任何註冊商。爲了演示部署過程,我註冊了 www.DjangoBoards.com域名。
如下是咱們將在本教程中使用的部署策略的概述:
雲是Digital Ocean提供的虛擬專用服務器。您可使用個人會員連接註冊Digital Ocean以得到免費的10美圓信用額度(僅適用於新賬戶)。
咱們將提供NGINX,由食人魔說明。NGINX將收到對服務器的全部請求。但若是請求數據,它不會嘗試作任何聰明的事情。它所要作的就是肯定所請求的信息是不是一個能夠自行提供的靜態資產,或者它是否更復雜。若是是這樣,它會將請求傳遞給Gunicorn。
NGINX還將配置HTTPS證書。這意味着它只接受經過HTTPS的請求。若是客戶端嘗試經過HTTP請求,NGINX將首先將用戶重定向到HTTPS,而後它纔會決定如何處理請求。
咱們還將安裝此certbot以自動續訂Let的加密證書。
Gunicorn是一個應用服務器。根據服務器具備的處理器數量,它能夠生成多個工做程序以並行處理多個請求。它管理工做負載並執行Python和Django代碼。
Django是努力工做的人。它能夠訪問數據庫(PostgreSQL)或文件系統。但在大多數狀況下,工做是在視圖內部完成,渲染模板,以及過去幾周咱們編寫過的全部內容。在Django處理請求以後,它會向Gunicorn返回一個響應,他將結果返回給NGINX,最終將響應傳遞給客戶端。
咱們還將安裝PostgreSQL,一個生產質量數據庫系統。因爲Django的ORM系統,很容易切換數據庫。
最後一步是安裝Supervisor。它是一個過程控制系統,它將密切關注Gunicorn和Django,以確保一切順利進行。若是服務器從新啓動,或者Gunicorn崩潰,它將自動重啓。
您可使用您喜歡的任何其餘VPS(虛擬專用服務器)。配置應該很是類似,畢竟咱們將使用Ubuntu 16.04做爲咱們的服務器。
首先,讓咱們建立一個新的服務器(在Digital Ocean上,他們稱之爲「Droplet」)。選擇Ubuntu 16.04:
選擇尺寸。最小的液滴足夠了:
而後爲您的Droplet選擇一個主機名(在個人狀況下爲「django-boards」):
若是您有SSH密鑰,則能夠將其添加到您的賬戶。而後,您將可以使用它登陸服務器。不然,他們會經過電子郵件向您發送root密碼。
如今選擇服務器的IP地址:
在咱們登陸服務器以前,讓咱們將域名指向此IP地址。這將節省一些時間,由於DNS設置一般須要幾分鐘才能傳播。
因此這裏咱們添加了兩條A記錄,一條指向裸域「djangoboards.com」,另外一條指向「www.djangoboards.com」。咱們將使用NGINX配置規範URL。
如今讓咱們使用您的終端登陸服務器:
ssh root@45.55.144.54 root@45.55.144.54's password:
而後你應該看到如下消息:
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:
設置新密碼,而後開始配置服務器。
sudo apt-get update sudo apt-get -y upgrade
若是在升級過程當中收到任何提示,請選擇「保持當前安裝的本地版本」選項。
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
監
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
使用如下命令建立新用戶:
adduser boards
一般,我只選擇應用程序的名稱。輸入密碼,並可選擇在提示中添加一些額外信息。
如今將用戶添加到sudoers列表:
gpasswd -a boards sudo
首先切換到postgres用戶:
sudo su - postgres
建立數據庫用戶:
createuser u_boards
建立一個新數據庫並將用戶設置爲全部者:
createdb django_boards --owner u_boards
爲用戶定義一個強密碼:
psql -c "ALTER USER u_boards WITH PASSWORD 'BcAZoYWsJbvE7RMgBPzxOCexPRVAq'"
咱們如今能夠退出postgres用戶了:
exit
切換到應用程序用戶:
sudo su - boards
首先,咱們能夠檢查咱們的位置:
pwd /home/boards
首先,讓咱們用咱們的代碼克隆存儲庫:
git clone https://github.com/sibtc/django-beginners-guide.git
啓動虛擬環境:
virtualenv venv -p python3.6
初始化virtualenv:
source venv/bin/activate
安裝要求:
pip install -r django-beginners-guide/requirements.txt
咱們將在這裏添加兩個額外的庫,Gunicorn和PostgreSQL驅動程序:
pip install gunicorn pip install psycopg2
如今在/ home / boards / django-beginners-guide文件夾中,讓咱們建立一個.env文件來存儲數據庫憑據,密鑰和其餘全部內容:
/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
如下是數據庫URL的語法:postgres:// db_user
:db_password
@ db_host
:db_port
/ db_name
。
如今讓咱們遷移數據庫,收集靜態文件並建立一個超級用戶:
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
如今靜態文件:
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' ...
此命令將全部靜態資產複製到外部目錄,NGINX能夠在該目錄中爲咱們提供文件。稍後會詳細介紹。
如今爲應用程序建立一個超級用戶:
python manage.py createsuperuser
所以,Gunicorn是負責在代理服務器後面執行Django代碼的人。
在/ home / boards中建立一個名爲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=-
此腳本將啓動應用程序服務器。咱們提供了一些信息,例如Django項目的位置,用於運行服務器的應用程序用戶等等。
如今讓這個文件可執行:
chmod u+x gunicorn_start
建立兩個空文件夾,一個用於套接字文件,另外一個用於存儲日誌:
mkdir run logs
如今/ home / boards裏面的目錄結構應該是這樣的:
django-beginners-guide/ gunicorn_start logs/ run/ staticfiles/ venv/
該staticfiles文件夾由建立collectstatic命令。
首先,在/ home / boards / logs /文件夾中建立一個空的日誌文件:
touch logs/gunicorn.log
如今建立一個新的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
保存文件並運行如下命令:
sudo supervisorctl reread sudo supervisorctl update
如今檢查狀態:
sudo supervisorctl status boards
boards RUNNING pid 308, uptime 0:00:07
下一步是設置NGINX服務器以提供靜態文件並將請求傳遞給Gunicorn:
在/ etc / nginx / sites-available /中添加一個名爲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; } }
建立指向已啓用站點的文件夾的符號連接:
sudo ln -s /etc/nginx/sites-available/boards /etc/nginx/sites-enabled/boards
刪除默認的NGINX網站:
sudo rm /etc/nginx/sites-enabled/default
重啓NGINX服務:
sudo service nginx restart
此時,若是DNS已經傳播,則該網站應在URL www.djangoboards.com上提供。
開始使用的最佳選擇之一是Mailgun。它提供了一個很是可靠的免費計劃,每個月包含12,000封電子郵件。
註冊一個免費賬戶。而後按照步驟操做,這很是簡單。您必須與您註冊域名的服務一塊兒工做。在個人例子中,它是Namecheap。
點擊添加域以向您的賬戶添加新域。按照說明操做,確保使用「mg。」子域名:
如今抓住第一組DNS記錄,它是兩個TXT記錄:
使用您的註冊商提供的網絡界面將其添加到您的域中:
對MX記錄作一樣的事情:
將它們添加到域中:
如今這一步不是強制性的,但因爲咱們已經在這裏,因此也要確認一下:
添加全部DNS記錄後,單擊「當即檢查DNS記錄」按鈕:
如今咱們須要有一些耐心。有時須要一段時間來驗證DNS。
同時,咱們能夠配置應用程序以接收鏈接參數。
的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] '
而後,個人本地計算機.env文件將以下所示:
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
個人生產.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 EMAIL_HOST=smtp.mailgun.org EMAIL_HOST_USER=postmaster@mg.djangoboards.com EMAIL_HOST_PASSWORD=ED2vmrnGTM1Rdwlhazyhxxcd0F
您能夠在Mailgun 的「 域信息」部分中找到您的憑據。
咱們能夠在生產服務器中測試新設置。在本地計算機上的settings.py文件中進行更改,將更改提交到遠程存儲庫。而後,在服務器中拉出新代碼並從新啓動Gunicorn進程:
git pull
使用電子郵件憑據編輯.env文件。
而後重啓Gunicorn進程:
sudo supervisorctl restart boards
如今咱們能夠嘗試啓動密碼重置過程:
在Mailgun儀表板上,您能夠得到有關電子郵件傳遞的一些統計信息:
如今讓咱們使用Let's Encrypt提供的一個很好的HTTPS證書來保護咱們的應用程序。
設置HTTPS從未如此簡單。更好的是,咱們如今能夠免費得到它。他們提供了一個名爲certbot的解決方案 ,負責爲咱們安裝和更新證書。這很是簡單:
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
如今安裝證書:
sudo certbot --nginx
只需按照提示操做便可。當被問及:
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
選擇2
將全部HTTP流量重定向到HTTPS。
有了這個,該網站已經經過HTTPS提供服務:
設置證書的自動續訂。運行如下命令編輯crontab文件:
sudo crontab -e
將如下行添加到文件末尾:
0 4 * * * /usr/bin/certbot renew --quiet
該命令將天天凌晨4點運行。全部在30天內到期的證書將自動續訂。