我們的博客雖然還有很多不完善的地方,但是沒關係,越早把它部署到互聯網上,才能越早發現線上特有的問題。現在也提倡漸進式開發,讓產品在迭代中快速成長。
部署考驗的不是你的 Django 編程水平,而是你對 Linux 的操作能力,以及對網絡通信的理解。多說無益,直接開幹!
配置服務器
要架設網站,首先你要有一臺連接到互聯網的服務器。國內比較出名的雲服務器屬阿里雲、騰訊雲、百度雲,三家各有優劣,大家自行了解比較,並選擇自己適合的購買。
利益相關:博主自己用的是阿里雲,所以教程會以阿里雲ECS作爲例子講解。新用戶通過推廣鏈接註冊有折扣和現金券(目前是20元);學生有優惠服務器每月9.5元,性能還不錯,很划算。如果你想用其他雲服務器,操作流程也差不多,不必擔心。
首先進入阿里雲ECS的購買頁面:
圖片字很小,看不清楚的同學將就一下放大看吧。
挑重點說一下:
- 實例從入門級裏選一款便宜的,以後流量高了再升級也不遲(土豪請無視這條)。
- 鏡像選擇 Ubuntu 16.04 64位。其他 Linux 版本也是可以的。
- 系統盤先選個 20G,夠你用一陣了。數據盤暫時用不上,不用勾選。
點擊下一步,來到網絡和安全組頁面:
這頁默認就行了,公網帶寬選最低的 1M ,初期夠用了。
點擊下一步,到系統配置頁面:
爲了後面遠程連接服務器更簡單,這裏勾選自定義密碼,也就是輸入用戶/密碼的認證方式了。實際上祕鑰對的認證方式更安全些,以後摸熟了再改回來吧。
點擊下一步,到分組設置頁面。這個頁面全部默認設置就好了。點擊下一步,確認訂單無誤後,就可以付款啦。
付款成功後,通過控制檯就可以看到已購買的雲服務器了:
這裏有時候會有黃字提醒你服務器的網絡端口沒開,點擊黃字鏈接去開通一下:
把 22(遠程連接端口)、443(HTTPS端口)、80(HTTP端口)都打開,3389端口順便也開了。
至此服務器的購買、配置就完成啦。稍等幾分鐘後等待初始化完成,就可以得到服務器的公網 IP 地址,博主的是 118.31.35.48
,後面會用到。
接下來就是正式的部署。
正式部署
開發時我們用的是 Django 自帶的開發服務器,但那個性能太差了,不可能用到線上環境。所以線上部署時,我們不僅要安裝 Django
,還要安裝 Nginx
和 Gunicorn
,這三兄弟的工作流程如下:
- 客戶端發來 http 請求,Nginx 作爲直接對外的服務器接口,對 http 請求進行分析
- 如果是靜態資源請求,則由Nginx自己處理(效率極高)
- 如果是動態資源請求,則把它轉發給 Gunicorn
- Gunicorn 對請求進行預處理後,轉發給 Django,最終完成資源的返回
如果用餐館來做比喻的話,Nginx 就是迎賓小姐,客人如果點了酒水,迎賓小姐自己就幫忙拿了;而 Gunicorn 是傳菜員,Django 是廚師,他兩一起滿足客人對現炒美食的需求。
遠程連接
部署的第一步就是想辦法連接到雲服務器上去,否則一切都免談。鑑於項目是在 Windows 環境開發的,推薦用 XShell 來作爲遠程連接的工具,非常的好用。XShell 有學校及家庭版本,填一下姓名和郵箱就可以免費使用了。千萬別嫌麻煩去下載來路不明的“綠色版”、“純淨版”,萬一有木馬你哭都哭不出來了。
XShell 怎麼使用就不贅述了,以讀者的聰明才智,稍微查閱一下就明白了。
使用相當簡單,基本就是把主機 IP、端口號(22)以及登錄驗證填好就能連接了。
連接成功後,就能在 XShell 窗口中看到阿里雲的歡迎字樣了:
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-151-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Welcome to Alibaba Cloud Elastic Compute Service !
root@dusaiphoto:~$
root@dusaiphoto:~$
是命令提示符,輸入命令時不需要你輸入這個。本文後面把 root@dusaiphoto:
字符省略掉,方便大家閱讀。
代碼部署
爲了防止系統太舊引起的各種麻煩,先升級一下庫的版本:
~$ sudo apt-get update
~$ sudo apt-get upgrade
完成之後,接着安裝需要的幾個包:
~$ sudo apt-get install nginx
~$ sudo apt-get install python3
~$ sudo apt-get install python3-pip
~$ sudo apt-get install git
~$ sudo pip3 install virtualenv
分別安裝了 nginx、python3、pip、git、virtualenv。其中 python3 和 pip3 的寫法是因爲阿里雲自帶了 Python2.7,把它們區分一下。之前開發時虛擬環境用的 python 自帶的,爲了避免讀者的版本不同造成的各類錯誤,穩妥起見用 virtualenv 庫來創建虛擬環境,操作步驟都是差不多的。
接下來就是要改一下 Django 的配置文件 settings.py
:
my_blog/settings.py
# 關閉調試模式
DEBUG = False
# 允許的服務器
ALLOWED_HOSTS = ['*']
# 靜態文件收集目錄
STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static')
- 部署時要關閉調試模式,避免安全性問題(此時 Django 就不再處理靜態資源了)。
ALLOWED_HOSTS
指明瞭允許訪問的服務器名稱或 IP,星號表示允許所有的請求。實際部署時請改成你的域名或 IP,比如ALLOWED_HOSTS = ['.dusaiphoto.com', '127.0.0.1']
。- 項目中有很多靜態文件,部署時需要找一個地方統一收集起來,也就是
STATIC_ROOT
指定的地址了。
因爲項目代碼需要通過 GitHub
倉庫進行下載(就像本教程的示例代碼一樣),因此修改完畢後需要把代碼上傳到 GitHub
。怎麼上傳這裏也不贅述了,博主之前寫過一篇《Win 10 連接 GitHub》的文章,有需要的讀者稍微讀一下。
需要注意的是,虛擬環境一般是需要在服務器上重新生成的,因此我們需要把開發中用到的庫列一個清單,以便在服務器上統一安裝。在本地虛擬環境中輸入:
pip freeze > requirements.txt
項目中就多了個 requirements.txt
文件,裏面記錄了項目需要的庫的清單。
教程爲了演示,上傳了媒體資源和數據庫,實際開發時可千萬不要上傳。
然後更新 Git 記錄並上傳到 GitHub。重新回到服務器的命令行,給項目代碼創建目錄並進入此目錄:
~$ mkdir -p /home/sites/dusaiphoto.com
~$ cd /home/sites/dusaiphoto.com
目錄位置是隨便你的,但建議找個地方統一管理所有的網站項目。
然後從 GitHub 中拉取項目代碼:
../dusaiphoto.com$ git clone https://github.com/stacklens/django_blog_tutorial.git
這裏拉取的博客教程的代碼。建議讀者先拉取教程代碼來測試,成功之後再重新部署自己的代碼。完成之後可以輸入 ls
指令,看看代碼文件夾是否正常生成了。
接着在服務器生成虛擬環境:
../dusaiphoto.com$ virtualenv --python=python3.5 env
../dusaiphoto.com$ source env/bin/activate
(env) ../dusaiphoto.com$
這裏用 virtualenv
生成並激活了虛擬環境。python 版本選擇 3.5 還是 3.7 都可以,區別並不大。
接下來就是安裝庫、收集靜態資源、數據遷移了:
(env) ../dusaiphoto.com$ cd django_blog_tutorial
(env) ../django_blog_tutorial$ pip3 install -r requirements.txt
(env) ../django_blog_tutorial$ python3 manage.py collectstatic
(env) ../django_blog_tutorial$ python3 manage.py migrate
代碼部署基本就完成了,接下來配置 Nginx
。
Nginx
前面我們安裝了 Nginx
,先來試試安裝是否正常。啓動 nginx 服務:
(env) ~$ sudo service nginx start
打開瀏覽器,輸入你的服務器公網 IP 地址:
Nginx 歡迎界面出現了,神奇吧。但這個默認配置顯然是不能用的,所以需要重新寫 Nginx 的配置文件。進入 /etc/nginx/sites-available
目錄,這裏是定義 Nginx 可用配置的地方。輸入指令 sudo vi dusaiphoto.com
創建配置文件並打開 vi 編輯器:
(env) ~$ cd /etc/nginx/sites-available
(env) /etc/nginx/sites-available$
(env) /etc/nginx/sites-available$ sudo vi dusaiphoto.com
關於 vi
編輯器如何使用也不贅述了,這裏只說兩個最基本的操作:
- 按
i
鍵切換到編輯模式,這時候纔可以進行輸入、刪除、修改等操作 - 按
Ctrl + c
退回到命令模式,然後輸入:wq + Enter
保存文件修改並退回到服務器命令行
回到正題,用 vi
在 dusaiphoto.com
文件中寫入:
server {
charset utf-8;
listen 80;
server_name 118.31.35.48; # 改成你的 IP
location /static {
alias /home/sites/dusaiphoto.com/django_blog_tutorial/collected_static;
}
location /media {
alias /home/sites/dusaiphoto.com/django_blog_tutorial/media;
}
location / {
proxy_set_header Host $host;
proxy_pass http://unix:/tmp/118.31.35.48.socket; # 改成你的 IP
}
}
此配置會監聽 80 端口(通常 http 請求的端口),監聽的 IP 地址寫你自己的服務器公網 IP。
配置中有3個規則:
- 如果請求 static 路徑則由 Nginx 轉發到目錄中尋找靜態資源
- 如果請求 media 路徑則由 Nginx 轉發到目錄中尋找媒體資源
- 其他請求則交給 Django 處理
如果你已經申請好域名了,就把配置中有 IP 的地方都修改爲域名,比如:server_name www.dusaiphoto.com;
寫好後就退出 vi
編輯器,回到命令行。因爲我們寫的只是 Nginx 的可用配置,所以還需要把這個配置文件鏈接到在用配置上去:
(env) ../sites-available$ sudo ln -s /etc/nginx/sites-available/dusaiphoto.com /etc/nginx/sites-enabled
至此 Nginx 就配置好了,接下來搞定 Gunicorn
。
有的讀者無論怎麼配置都只能看到 Nginx 歡迎頁面,有可能是 sites-enabled 目錄中的 default 文件覆蓋了你寫的配置。將 default 文件刪掉就可以正常代理自己的配置文件了。
Gunicorn及測試
先回到項目所在的目錄,並且進入虛擬環境,然後輸入:
(env) ../django_blog_tutorial$ pip3 install gunicorn
(env) ../django_blog_tutorial$ sudo service nginx reload
(env) ../django_blog_tutorial$ gunicorn --bind unix:/tmp/118.31.35.48.socket my_blog.wsgi:application
這裏的三個步驟分別是:
- 安裝
Gunicorn
- 重啓
Nginx
服務 - 啓動
Gunicorn
啓動 Gunicorn 也是一樣,如果你已經有域名了,就把套接字中的 IP 地址換成域名;wsgi 字眼前面是項目的名稱。另外
sudo service nginx reload
可替換成sudo service nginx restart
,區別是 reload 只重載配置文件,restart 重啓整個服務。
接下來用瀏覽器訪問服務器試一下:
大功告成啦,撒花慶祝!
後續工作
遺留問題
成功部署到線上後,還有些小問題沒解決。
第一個問題是進入文章詳情頁面, ckeditor 無法加載了,並且瀏覽器報出 prism_patched.js Not Found
的錯誤。這個問題的根源在於之前我們在開發 ckeditor 的代碼高亮功能時,prism
模塊是直接插入到虛擬環境的庫中的,但問題是部署時虛擬環境是需要重新建立的,所以就缺少了這個 prism 插件導致報錯。
解決辦法也很簡單,在虛擬環境中找到 prism 插件的位置:
..\env\Lib\site-packages\ckeditor\static\ckeditor\ckeditor\plugins\prism
然後把它原封不動的複製到項目的 static
中完全相同的目錄中去:
my_blog\static\ckeditor\ckeditor\plugins\prism
這樣做行得通的原因是 django-ckeditor 也是一個 app,Django 訪問 app 資源時會優先在項目中搜索,沒有才去虛擬環境裏搜索。
然後就是通過 GitHub 更新服務器代碼,並且重新收集靜態文件:
(env) ../django_blog_tutorial$ git pull origin master
(env) ../django_blog_tutorial$ python3 manage.py collectstatic
這個問題給我們的啓示就是:針對三方庫、資源的改動最好不要直接修改源文件或環境,而是想辦法在項目副本中更改,這樣更便於維護。
有讀者發現舊的富文本評論中的表情沒顯示,這個別擔心,新發表的評論是沒問題的。
第二個問題是 GitHub 登錄不正常了,這個多半不是代碼的問題,而是你的服務器以及 GitHub 的回調配置問題。這裏也不展開講了,請讀者返回前面第三方登錄的文章再研究下。
第三個問題是開發階段用的 sqlite
數據庫雖然很方便,但是性能較差。線上以性能爲王,所以需要將數據庫更換爲 MYSQL
這類主流的高性能數據庫。遠程安裝配置 MYSQL 的方法可以參考一下劉江的博客,講得很清楚。
第四個問題是教程部署是以 root 用戶進行的,這是服務器中具有最高權限的用戶,除掉自身的瞎操作,一旦被攻擊者登錄了會相當慘烈(尤其是用戶/密碼的登錄方式,安全係數極低)。比較好的方式是重新創建一個普通用戶來進行部署,並且將登錄方式改爲祕鑰對。
後期運維
你的網站是需要不斷更新優化代碼的。每次修改代碼後,更新到服務器上也很簡單。在虛擬環境中並進入項目目錄,依次(collectstatic 和 migrate 是可選的)執行以下命令:
git pull origin master
python3 manage.py collectstatic
python3 manage.py migrate
# 重啓 gunicorn
pkill gunicorn
gunicorn --bind unix:/tmp/118.31.35.48.socket my_blog.wsgi:application
加上 cd
更改目錄的指令,部署過程有十幾條指令,手動輸入也太麻煩了。簡單粗暴的辦法是利用 XShell 的宏,把部署指令寫成順序執行的腳本,點幾個按鈕就完成了,非常方便。
更高級的做法是在服務器上編寫自動化部署的腳本,這個就讀者以後慢慢研究吧
如果你更改了 Nginx 的配置文件,還需要重啓 Nginx 服務:
sudo service nginx reload
最後,還記得前面章節開發的日誌記錄功能不?看看項目中有 logs
目錄嗎?
域名及優化
相對部署來說,域名配置就很容易了。阿里雲提供域名的購買、備案(頂級域名必須,約10個工作日)、解析服務,簡直全家桶有沒有。重點提醒有了域名之後要改的地方:
settings.py
中的ALLOWED_HOSTS
Nginx
中與 IP/域名 有關的位置Gunicorn
中與 IP/域名 有關的位置
域名搞定之後,接着就可以着手考慮把網站升級爲 https 版本了,這是大趨勢,一定要做。(這個也留給讀者自己折騰)
另外,開發時爲了效率把所有靜態資源都下載到本地,但是部署時不推薦這樣做,原因是靜態文件通常體積都較大,你花血汗錢買的服務器載入會很慢。儘量遠程 CDN 調用,像這樣:
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
國內推薦BootCDN,速度快還免費。
媒體資源也是類似,小圖還無所謂,大圖就要放在七牛雲這類的對象存儲雲上,否則你網頁的載入速度會很悲劇的。
最後再次提醒,在開發時我們往 settings.py
中寫入如 SECRET_KEY 、郵箱密碼等各種敏感信息,部署時千萬不要直接上傳到互聯網(GitHub 庫是公開的!),而是把這些信息寫到服務器本地,然後在 settings.py
中讀取。
總結
部署可以說是入門者最大的難關了,也是檢驗成果、獲取成就感的關鍵一步。多查資料,要相信你遇到的問題別人早就遇到過了。
部署是菜鳥的畢業禮,也是新人的第一課。
路漫漫其修遠兮,吾將上下而求索。
- 有疑問請在杜賽的個人網站留言,我會盡快回復。
- 或Email私信我:[email protected]
- 項目完整代碼:Django_blog_tutorial