部署前准備
在Linux上部署Django項目目前主流的都是采用Nginx代理,本文介紹在服務器環境為 Centos 7 下通過 Nginx + Gunicorn 方式部署 Django 項目,在 Windows Server 下部署查看: 在 Windows Server 通過IIS 部署 Django 項目。
1、購買服務器
在 linux 上部署時,一般有兩種選擇。centos系統使用較多,新人可以選擇有桌面環境的 ubuntu 系統。學生優惠9.9 元/月購買地址:阿里雲服務器學生專區、騰訊雲服務器學生專區。本文介紹的是 Centos7 的部署。
2、購買域名
阿里雲域名注冊地址: 域名注冊系統,根據需求購買即可。
3、解析域名到服務器
域名解析前需要先將綁定到服務器:綁定域名 ,隨后解析域名:解析域名
4、登錄到服務器
服務器通常位於雲端,需要使用遠程登錄工具登錄后才能對服務器進行操作。如何登錄到 Linux : 登錄 Linux 實例
5、創建新用戶
如果是一台全新服務器的話,通常我們是以 root 用戶登錄的。在 root 下部署代碼不安全,最好是建一個新用戶(如果你已經以非 root 用戶登錄的話可以跳過這一步)
# 創建新用戶crime
adduser crime
# 配置密碼
passwd crime
# 把新創建的用戶加入超級權限組
usermod -a -G crime
# 切換到創建的新用戶
su - crime
安裝Python
1、安裝編譯相關工具
# 更新系統軟件包
yum update -y
# 安裝軟件管理包和可能使用的依賴
yum -y groupinstall "Development tools"
# 為centos系統增加編譯功能
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
# Python3.7需要的依賴包libffi-devel
yum install libffi-devel -y
2、下載安裝包解壓
# 指定下載目錄
cd /home
# 下載
wget https://www.python.org/ftp/python/3.7.2/Python-3.7.2.tar.xz
# 解壓
tar -xvJf Python-3.7.2.tar.xz
3、編譯安裝
# 創建編譯安裝目錄
mkdir /usr/local/python3
# 進入解壓目錄
cd /home/Python-3.7.2
# 編譯安裝到指定路徑
./configure --prefix=/usr/local/python3
# 安裝
make && make install
4、添加軟鏈接
# 建立軟鏈接
ln -s /usr/local/python3/bin/python3 /usr/local/bin/python3 #一般/usr/bin系統應用,/usr/local/bin/用戶安裝應用
# 建立pip3軟鏈接
ln -s /usr/local/python3/bin/pip3 /usr/local/bin/pip3
#驗證安裝
python3 -V
pip3 -V
配置虛擬環境
1、安裝Virtualenv
pip3 install virtualenv
# 建立軟鏈接
ln -s /usr/local/python3/bin/virtualenv /usr/local/bin/virtualenv
2、配置項目虛擬環境
首先設計好服務器項目目錄結構,一台服務器可能部署多個網站,所有網站代碼都放在 sites 目錄下。
|-- home
| |-- crime #用戶名,便於區分
| |-- sites #站點,便於管理多個項目
| |-- demo.eosones.com #每個項目用域名區分
| |-- Myblog #項目目錄
| |-- Myblog_env #項目虛擬環境
創建項目虛擬環境
#創建項目目錄結構
mkdir -p /home/crime/sites/demo.eosones.com
# 切換到項目地址
cd /home/crime/sites/demo.eosones.com
# 創建項目虛擬環境
virtualenv --python=/usr/local/bin/python3 Myblog_env
常用命令
# 進入啟動目錄
cd /home/crime/sites/demo.eosones.com/Myblog_env/bin
# 激活
source activate
# 退出
deactivate
在命令行前面出現(Myblog_env)說明是成功進入虛擬環境。
安裝Mysql
1、yum下載安裝
# 檢測系統是否自帶安裝 MySQL
rpm -qa | grep mysql
# 下載
cd /home/
wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm
# 安裝
rpm -ivh mysql80-community-release-el7-3.noarch.rpm
# 更新 yum 緩存
yum update
# 查看要安裝的MySQL版本
yum repolist all | grep mysql
# 安裝
yum install mysql-server
2、啟動
# 權限設置
chown mysql:mysql -R /var/lib/mysql
# 初始化 MySQL
mysqld --initialize
# 啟動 MySQL
systemctl start mysqld
# 查看 MySQL 運行狀態
systemctl status mysqld
# 驗證 MySQL
mysqladmin --version
3、登錄
# 查看初始化密碼
grep 'temporary password' /var/log/mysqld.log
# 登錄
mysql -u root -p 臨時密碼
# 更改超級用戶帳戶密碼
ALTER USER 'root'@'localhost' IDENTIFIED BY '更改的密碼';
4、常用mysql服務命令
# 登錄mysql
mysql -u username -p
# 退出mysql
quit
# 啟動mysql
systemctl start mysqld.service
# 結束
systemctl stop mysqld.service
# 重啟
systemctl restart mysqld.service
# 開機自啟
systemctl enable mysqld.service
本地項目搬遷到服務器
1、部署前的項目配置
在本地環境中配置中DEBUG =True
,Django會在STATICFILES_DIRS
目錄下尋找靜態文件,但在生產環境為了安全起見,需要關閉 DEBUG 選項並設置允許訪問的域名,此時django.contrib.staticfiles
失效,為了能夠方便地讓 Nginx 處理這些靜態文件的請求,需要在項目的配置文件里做一些必要的配置。
#Myblog/settings.py
# 關閉
DEBUG = False
# 添加域名
ALLOWED_HOSTS = ['127.0.0.1', 'localhost ', '.eosones.com'] #允許訪問該域名及其下的子域名
# 其他配置(作為前綴映射STATIC_ROOT)
STATIC_URL = '/static/'
# 配置收集靜態文件目錄
STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static')
#測試環境靜態文件目錄(失效)
STATICFILES_DIRS=(
os.path.join(BASE_DIR,'static'),
)
2、遷移依賴包
激活並進入本地測試虛擬環境,執行:
pip freeze > requirements.txt
此時包依賴信息將保存本地虛擬環境下的 requirements.txt 文件中,注意在有些包安裝前需要依賴其他包的需要手動調整一下順序。
然后上傳文件到服務器:
# 本地Centos上傳到Centos服務器
scp /path/requirements.txt root@服務器IP:/home #指定上傳位置
root@106.52.246.233's password: 輸入root密碼
# 本地 windowss上傳到Centos服務器(使用PuTTy的pscp功能)
cd D:\PuTTy #切換到PuTTy根目錄
pscp E:\myblog.sql root@服務器IP:/home #指定文件與上傳位置
上傳到服務器后,在激活虛擬環境下執行:
pip3 install -r /home/requirements.txt
pip就會自動從網上下載並安裝所有包,此時虛擬環境已經完全遷移到服務器。
3、遷移數據庫
使用Sqlite數據庫的話,直接打包數據庫文件上傳到服務器即可。使用Mysql數據庫,服務器上需要先安裝Mysql數據庫軟件,並要先在本地Mysql里備份導出數據。
# 選擇導出目錄
cd /home
# 導出本地Mysql數據(Win進入Mysql所在bin目錄下)
mysqldump -uroot -ppassword myblog>myblog.sql # myblog為你的項目數據庫名字
通過上面的命令將 myblog.sql 上傳到服務器home文件夾下,進行遷移。
# 登錄服務器Mysql
mysql -uroot -ppassword
# 選擇目標數據庫
use myblog;
source /home/myblog.sql
4、遷移項目
為了方便將代碼拉取到拉取到服務器與后期完善代碼,可以代碼上傳到 GitHub 等代碼托管平台 ,需要在本地與服務器安裝GIT:如何安裝GIT與配置教程、如何添加遠程庫Github
# 切換項目目錄
cd /home/crime/sites/demo.eosones.com
# 克隆項目
git clone https://github.com/CRIME-Z/Myblog.git Myblog #項目克隆到本地並命名為Myblog
# 查看
[root@demo.eosones.com] # ls
Myblog Myblog_env
5、收集靜態文件
虛擬環境下繼續運行 python manage.py collectstatic 命令收集靜態文件到之前配置的 collect_static 目錄下:
python manage.py collectstatic
完成全部遷移后,激活虛擬環境,測試項目是否成功運行。
python3 manage.py runserver 0.0.0.0:80
此時可以通過外網IP訪問,因為我們關閉了Django靜態文件功能,所以目前還無法加載靜態文件,之后我們會用 Nginx 進行代理。
安裝和配置 Gunicorn
Gunicorn 一般用來管理多個進程,有進程掛了Gunicorn 可以把它拉起來,防止服務器長時間停止服務,還可以動態調整 worker 的數量。
1、安裝測試
在虛擬環境下,安裝 Gunicorn:
pip3 install gunicorn
測試 Gunicorn 是否能啟動你的項目服務
# 切換項目目錄
cd /home/crime/sites/demo.eosones.com/Myblog
# 啟動
gunicorn --bind 0.0.0.0:8000 Myblog.wsgi:application
瀏覽器輸入域名,可以看到訪問成功了。
2、添加自啟動
為了使用方便,創建一個 Gunicorn Systemd Service 文件,直接運行以下命令(退出虛擬環境)
vim /etc/systemd/system/gunicorn.service
配置如下:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=cimre
Group=www-data
WorkingDirectory=/home/crime/sites/demo.eosones.com/Myblog
ExecStart=/home/crime/sites/demo.eosones.com/Myblog_env/bin/gunicorn --workers 3 --bind unix:/home/crime/sites/demo.eosones.com/Myblog.sock Myblog.wsgi:application
[Install]
WantedBy=multi-user.target
User
填寫自己當前用戶名稱、WorkingDirectory
填寫項目的地址、ExecStart
中第一個地址是虛擬環境中 gunicorn 的目錄,--bind
中使用IP:端口或者套接字,防止端口沖突。
文件配置完成之后,使用下面的命令啟動服務:
# 重新加載systemctl
systemctl daemon-reload
之后就可以使用systemctl命令控制Gunicorn服務
# 查看Gunicorn服務狀態
systemctl status gunicorn
# 開啟Gunicorn服務
systemctl start gunicorn
# 關閉Gunicorn服務
systemctl stop gunicorn
# 開機自啟
systemctl enable gunicorn
# 重啟Gunicorn服務
systemctl restart gunicorn
# 查看日志
journalctl -u gunicorn
配置Nginx
Nginx 是一個高性能的負載均衡HTTP和反向代理服務器,可以高效地處理靜態文件請求,由於其底層使用 epoll 異步IO模型進行處理,使其深受歡迎。在 CentOS7 中可以通過yum命令yum install nginx
安裝Nginx應用,會自動配置好相關 Nginx 服務,本文介紹手動編譯安裝配置。
1、下載編譯安裝
# 指定下載目錄
cd /home
# 下載
wget http://nginx.org/download/nginx-1.16.0.tar.gz
# 解壓
tar -zxvf nginx-1.16.0.tar.gz
# 進入解壓目錄
cd /home/nginx-1.16.0
# 編譯安裝到指定路徑
./configure --prefix=/usr/local/nginx
# 安裝
make && make install
# 查找安裝路徑
whereis nginx
2、Nginx常用命令:
# 啟動
/usr/local/nginx/sbin/nginx
# 指定配置文件啟動
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
# 快速停止
/usr/local/nginx/sbin/nginx -s stop
# 完整有序的停止
/usr/local/nginx/sbin/nginx -s quit
#重啟
/usr/local/nginx/sbin/nginx -s reload
#測試nginx配置文件是否正確
/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
# 檢查nginx是否已經啟動
ps -aux | grep nginx
# 強制停止
pkill -9 nginx
啟動成功后,通過外網IP訪問即可看到下面頁面:
3、添加自啟動
為了使用方便,現將 Nginx 服務添加至 systemctl ,CentOS7 的服務 systemctl 腳本存放在/usr/lib/systemd/
下,有系統(system)和用戶(user)之分,需要開機不登陸就能運行的程序,存在系統服務里,即/usr/lib/systemd/system
目錄下。
Nginx 服務關閉情況下,通過vi命令打開服務配置:
vi /usr/lib/systemd/system/nginx.service
編輯如下代碼:
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
#
ExecStartPre=/usr/bin/rm -f /usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf #啟動准備
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf #啟動命令
ExecReload=/usr/local/nginx/sbin/nginx -s reload #重啟命令
ExecStop=/usr/local/nginx/sbin/nginx -s stop #停止命令
ExecQuit=/usr/local/nginx/sbin/nginx -s quit #快速停止
KillSignal=SIGQUITTimeoutStopSec=5
KillMode=process
PrivateTmp=true
[Install]
WantedBy=multi-user.target
路徑修改為對應的路徑即可,在編譯安裝的情況下,PIDFile 默認位置一般為/usr/local/nginx/logs/nginx.pid
,在二進制包安裝方式下,PIDFile 默認位置一般為/run/nginx.pid
,這個位置在 /usr/lib/systemd/system/nginx.service 中配置需與nginx.conf 文件中的保持一致。
#配置754的權限
chmod 754 /usr/lib/systemd/system/nginx.service
# 重新加載systemctl
systemctl daemon-reload
之后就可以進行systemctl操作:
# 查看狀態
systemctl status nginx
# 啟動
systemctl start nginx
# 重啟
systemctl reload nginx
# 停止
systemctl stop nginx
# 開機自啟動
systemctl enable nginx
4、部署配置
首先到安裝位置下 /usr/local/nginx/conf/ 中先備份一下nginx.conf配置文件,以防意外。
cp nginx.conf nginx.conf.bak
然后打開 nginx.conf 並修改以下內容:
vim /usr/local/nginx/conf/nginx.conf
# 修改位置
server {
# 端口和域名
listen 80;
server_name www.eosones.com 0.0.0.0;
# static 和 media 的地址
location /static {
alias /home/crime/sites/demo.eosones.com/Myblog/collect_static;
}
location /media {
alias /home/crime/sites/demo.eosones.com/Myblog/media;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http//:unix:/home/crime/sites/demo.eosones.com/Myblog.sock; #端口或者套接字要和gunicorn里配置的一樣
}
Nginx通過根據server_name域名得知訪問哪個項目,監聽請求80端口,首先 location 會匹配到靜態文件的URL ,其請求均由 Nginx 處理,alias 指明了靜態文件的存放目錄。其它請求轉發給 Django 處理,proxy_pass 后面配置需與gunicorn配置相同。
# 把 nginx 加入超級權限組
usermod -a -G root nginx
# 配置項目文件夾權限
chmod 710 -R /home/
以后如果更新了代碼,只要運行下面的命令重啟一下 Nginx 和 Gunicorn 就可以使新的代碼生效了:
# 更改配置執行
systemctl daemon-reload
# 更改代碼執行
systemctl restart gunicorn
systemctl restart nginx
其他優化
1、多站點部署配置
在上面的部署中我們直接在默認主配置文件 /usr/local/nginx/conf/ngnix.conf 中進行的配置,為了方便一台服務器需要部署多個項目,進入 Nginx 的配置文件目錄/usr/local/nginx/conf/,然后新建一個目錄:
mkdir vhost
首先使用 /usr/local/nginx/conf/ 目錄下的原來默認的 nginx.conf 文件,修改相應的代碼:
http {
include mime.types; # nginx支持的媒體類型庫文件
default_type application/octet-stream; #默認的媒體類型
sendfile on; #開啟高效傳輸模式
keepalive_timeout 65; #連接超時時間 65秒
include /usr/local/nginx/conf/vhost/*.conf; #主要是這個地方,把原來的配置文件包含進來
server {
listen 80 default_server;
server_name _;
return 404;
}
}
最后為每個站點配置如下,並且移動到 /usr/local/nginx/conf/vhost 下即可
#Myblog.conf
server {
# 端口和域名
listen 80;
server_name www.eosones.com;
# static 和 media 的地址
location /static {
alias /home/crime/sites/demo.eosones.com/Myblog/collect_static;
}
location /media {
alias /home/crime/sites/demo.eosones.com/Myblog/media;
}
location / {
proxy_pass http//:unix:/home/crime/sites/demo.eosones.com/Myblog.sock; #端口或者套接字要和gunicorn里配置的一樣
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2、使用 CDN 加載速度
我們的項目使用了 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>
3、問題匯總
如果本地開發環境為windows,部署到Linux服務器需注意:
linux目錄名、文件名、文件后綴、Mysql 表名等都要區分大小寫
外網無法訪問:
有些服務器外網默認是無法訪問的,因為防火牆不允許,所以要開啟防火牆,讓其可以訪問需要訪問的端口號。
firewall-cmd --get-active-zones
# 打開80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
# 重啟防火牆
firewall-cmd --reload
# 查看端口號是否開啟
firewall-cmd --query-port=80/tcp
有些服務器在防火牆里開啟端口之后還不能訪問,那就需要到對應的服務器提供商的管理后台安全組里開啟對應的端口才能正常訪問。
配置完成后無法加載靜態媒體文件:
首先確保配置目錄正確並python manage.py collectstatic
收集過靜態文件
# Myblog/settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static')
# /usr/local/nginx/conf/ngnix.conf
location /static {
alias /home/crime/sites/demo.eosones.com/Myblog/collect_static;
}
location /media {
alias /home/crime/sites/demo.eosones.com/Myblog/media;
}
確保Nginx具有項目目錄的訪問權限
# 查看nginx日志
less /usr/local/nginx/logs/error.log
# 如果是Permission denied 問題
chmod -R 777 /home # -R 是指級聯應用到目錄里的所有子目錄和文件,777 是所有用戶都擁有最高權限