Django 服務部署(Nginx+uWSGI)

現有的腳本、工具想找個統一的地方能讓開發和其他人員使用,就想弄個網站。調研了下,發現Django不錯,雖然都說性能不好,但上手快、敏捷開發,符合我們內部使用需求,就用他了。下面記錄我搭建Django服務的過程

一、申請服務器(阿里云、騰訊云等等,略)

注:下面的命令是在linux下的,如果是CentOS的,把相應命令改成yum的命令即可

二、安裝和開d發環境一致的python版本

1、安裝python3.6

apt-get install software-properties-common 
add-apt-repository ppa:jonathonf/python-3.6 
apt-get update 
apt-get install python3.6

2、創建軟連接

cd /usr/bin 

# 如果還需要保留python2的,則下面刪除python的軟連接不用操作
rm python 
ln -s python3.6 python  
rm python3 
ln -s python3.6 python3

3、安裝pip

apt-get install python3-pip 

pip3 install --upgrade pip

如果是CentOS系統,可以參考這篇文章

4、安裝虛擬環境(可選)

pip3 install virtualenv

5、創建虛擬環境(可選)

virtualenv mysite_env  #創建虛擬環境

source mysite_env/bin/activate  # 進入虛擬環境
deactivate #退出虛擬環境

若出現找不到virtualenv命令提示,可參考這篇文章

三、安裝Git(或其他的代碼管理工具)

# 安裝Git
apt-get install git

# clone項目代碼
git clone XXX項目地址

CentOS系統下編譯安裝(yum安裝的版本過低)可參考這篇文章

四、安裝項目依賴包

1、生成、安裝依賴包

# 在開發環境生成requirements.txt文件

pip freeze >requirements.txt

# 由于默認的pip freeze命令生成的依賴包是你環境下所有的包,不是跟你項目相關的包也會生成,可能會有很多,所以這里我使用第三方包 pipreqs

pipreqs ./

# pipreqs 會去遍歷你項目目錄,盡可能的識別你的依賴包,但可能會遺漏,需要你檢查下

# 在服務器上安裝依賴文件

pip install -r requirements.txt

2、安裝依賴包時報錯的解決

  • 問題1:安裝mysqlclient出現“OSError: mysql_config not found”錯誤

    解決方法:

apt-get install libmysqlclient-dev python3-dev

# CenOS系統下的命令

yum install mysql-devel gcc gcc-devel python-devel
  • 問題2:matplotlib安裝報錯

    解決方法見這篇文章

  • 問題3: 提示xadmin-2.0.1找不到,這是因為xadmin針對Django2版本的包是手動安裝的(增強的后臺管理插件,不需要的可不裝)

    解決方法:

# 手動安裝
pip install git+git://github.com/sshwsfc/xadmin.git@django2

五、安裝配置mysql數據庫

1、安裝mysql

wget https://dev.mysql.com/get/mysql-apt-config_0.8.10-1_all.deb 

dpkg -i mysql-apt-config_0.8.10-1_all.deb 
apt-get update 
apt-get install mysql-server 

# 然后設置密碼

CentOS系統下安裝mysql可參考這篇文件(mysql5.6)

2、配置數據庫(配置文件一般在/etc/my.cnf 文件里)

[mysqld]
# 設置默認使用的端口
port=3306 
# 允許最大連接數
max_connections=200 
# 允許連接失敗的次數。這是為了防止有人試圖攻擊數據庫
max_connect_errors=10 
# 服務端使用的字符集
character-set-server=utf8mb4 
# 數據庫字符集對應一些排序等規則使用的字符集
collation-server=utf8mb4_general_ci 
# 創建新表時將使用的默認存儲引擎
default-storage-engine=INNODB 
# 默認使用“mysql_native_password”插件作為認證加密方式
# MySQL8.0默認認證加密方式為caching_sha2_password
default_authentication_plugin=mysql_native_password

3、創建用戶、創建庫

#進入數據庫
mysql -u root -p 

# 創建庫
CREATE DATABASE mysite_db DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci

# 創建用戶
CREATE USER 'test’@‘localhost’ IDENTIFIED BY ’Test123456@‘;
# 用戶授權該表全部權限
GRANT ALL PRIVILEGES ON mysite_db.* TO ’Test123456@‘;
# 刷新入庫生效
FLUSH PRIVILEGES;

4、數據庫導出導入

# 從開發庫里導出
mysqldump -u root -p mysite_db > data.sql

# 把data.sql文件拷到服務器上(可以用工具,也可以用scp命令)
scp data.sql root@xx.xx.xx.xx:/home/data.sql

# 進入服務器數據庫
mysql -u root -p mysite_db

# 導入數據文件
source data.sql;

5、如果不是通過數據庫導入方式建表的,那重新創建表即可

python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py createcachetable  # 緩存表的名稱需在setting文件里已設置

六、測試啟動

啟動測試下,服務是否正常

python3 manage.py runserver 0.0.0.0:80

七、用Nginx+uWSGI部署

1、安裝uwsgi(可參考官方文檔)

# 安裝uwsig
pip3 install uwsgi

2、基礎測試
創建一個名為 test.py的文件,vim編輯文件:

def application ( env,start_response ):
    start_response ('200 OK',[('Content-Type','text / html' )])
    return  [ b “Hello World” ]  #python3 

3、測試運行

uwsgi --http:8000 --wsgi-file test.py  
# 說明 --http :8000 使用http協議 端口8000  --wsgi-file test.py 加載指定文件
# 如果出現HelloWorld說明可用

# 如果出現--- no python application found, check your startup logs for errors —錯誤,說明python版本有多個,而你的uwsgi不是裝在默認的那個python里,所以可以在虛擬機里創建一個只有一個python的環境啟動,或者在/etc/profile里把python路徑改成安裝uwsgi的python路徑
# 訪問不了,還有可能是服務器沒有開放8000端口,比如阿里云是默認關閉8000端口的,去開啟即可

4、使用uwsgi測試你的項目

# 進入的項目文件夾(與manage.py同一級) 

# 確保項目可以正常工作

python3 manage.py runserver 0.0.0.0:8000

# 如果發現django模塊不能導入,則是因為沒有添加環境變量,具體命令如下:vim ~/.bash_profile,添加django的路徑export PATH=$HOME 在此部分添加,用冒號隔開,具體格式請搜索 $PATH。

# 如果地址不能訪問,檢查django項目的settings.py設置,把 ALLOWED_HOSTS = [] 改為 ALLOWED_HOSTS = ['*’]

# 如果還是不能訪問,查看8000端口是否開放

# 用uwsgi運行項目

uwsgi --http :8000 --chdir /home/mysite --home /home/mysite_env --module mysite.wsgi:application

# 上面具體參數設置可見[官方文檔](https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/uwsgi/#configuring-and-starting-the-uwsgi-server-for-django)

5、安裝nginx(CentOS)

# 安裝nginx(已裝過的可略)

# 下載

wget [http://nginx.org/download/nginx-1.14.1.tar.gz](http://nginx.org/download/nginx-1.14.1.tar.gz)

# 解壓

tar -xzvf nginx-1.14.1.tar.gz

# 進入目錄

cd nginx-1.14.1/

# 安裝依賴

yum install -y pcre pcre-devel

yum install -y openssl openssl-devel

# 創建Nginx的用戶組及用戶

groupadd nginx

useradd -s /sbin/nologin -M -g nginx nginx

# 編譯及安裝

./configure --user=nginx --group=nginx --prefix=/usr/local/nginx   --with-http_stub_status_module --with-http_ssl_module

make && make install

# 檢查并啟動(以下三個命令都要運行)

/usr/local/nginx/sbin/nginx -t   # 測試nginx.conf的配置是否正確  

/usr/local/nginx/sbin/nginx  # 直接啟動

/usr/local/nginx/sbin/nginx -s reload  # 重啟

/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf  # 根據nginx.conf里的配置,啟動nginx服務  

# 具體可參考[Linux(CentOS 6.5) 下Nginx 安裝,重啟和停止](https://blog.csdn.net/greensomnuss/article/details/80986238)

6、配置nginx(CentOS)

# 將/usr/local/nginx/conf目錄下的uwsgi_params文件復制到你的項目目錄
cp /usr/local/nginx/conf/uwsgi_params /home/mysite/

 
# 創建myconfs文件夾 
mkdir /home/myconfs

 
# 創建一個名為mysite_nginx.conf的文件(可以在任意路徑,只要你能找到,這里我把它放在/home/myconfs/)
vim /home/myconfs/mysite_nginx.conf
# 按自己路徑寫入配置信息(如下)

具體配置(可見nginx文檔)

upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # 你的網站監聽的端口,此處先用8000端口測試,正式部署可以改為80或其他
    listen      8000;
    # 你的網站的域名
    server_name *.com; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /home/mysite/media;  # 你的media的文件目錄
    }

    location /static {
        alias /home/mysite/collected_static; # 你的項目收集的靜態文件目錄(后邊會將收集靜態文件)
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /home/mysite/uwsgi_params; # uwsgi_params 文件所在目錄
    }
}

# 這個配置文件告訴nginx提供來自文件系統的媒體和靜態文件,以及處理那些需要Django干預的請求。對于一個大型部署,讓一臺服務器處理靜態/媒體文件,讓另一臺處理Django應用,被認為是一種很好的做法,但是現在,這樣就好了。

讓nginx的根文件載入你的mysite_nginx.conf配置的信息:
vim /usr/local/nginx/conf/nginx.conf


7、部署靜態文件

# 在運行nginx之前,你必須收集所有的Django靜態文件到靜態文件夾里
# 編輯項目的settings   
vim /home/mysite/mysite/settings.py
#添加 
STATIC_ROOT = os.path.join(BASE_DIR, "collected_static/")

 
# 然后運行(如果之前用虛擬環境的,記得進入虛擬環境再操作) 
python3 manage.py collectstatic

8、基本的nginx測試

# 啟動nginx

/usr/local/nginx/sbin/./nginx

# 如果已經啟動,則重啟

/usr/local/nginx/sbin/./nginx -s reload

# 要檢查是否正確的提供了媒體文件服務,上傳一張圖片(這里我上傳的文件為 1.jpg)到 /home/sysite/media文件夾中

# 然后訪問[http://example.com:8000/media/1.jpg](http://example.com:8000/media/1.jpg) - 如果這能正常工作,那么至少你知道nginx正在正確的提供文件服務。

# 最好將你的nginx先停止, 再開啟,而不是重載

9、配置uwsgi,創建ini文件方便處理。ini參考如下
創建一個名為mysite_uwsgi.ini的文件

[uwsgi] 
chdir = /home/mysite  # 你的項目目錄
home = /home/mysite_env # 如果有虛擬環境,則需要指定虛擬環境目錄; 沒有則注釋掉
module = mysite.wsgi:application  # 指向自己Django項目目錄下mysite目錄下的wsgi文件
master = True 
processes = 4  # 使用進程數
harakiri = 60  # 最大超時時間
max-requests = 5000  # 最大請求數,到了后就會自動重啟
socket = 127.0.0.1:8001  # socket連接地址和端口,和之前nginx配置一致
pidfile = /home/mysite_uwsgi/master.pid  # 在失去權限前,將pid寫到指定的pidfile文件中
daemonize = /home/mysite_uwsgi/mysite.log # 使進程在后臺運行,并將日志打到指定的日志文件或者udp服務器
# chmod-socket    = 664  # 如果沒有權限訪問uWSGI的socket,這里可以設置權限
vacuum = True  # 服務退出或重啟,自動刪除pid和socket文件

10、運行uWSGI

uwsgi -d --ini mysite_uwsgi.ini
# 參數 -d 為后臺運行。此時你的django項目已經部署成功。
# 注意,必須nginx也要啟動才能正常訪問

11 、官方參考地址

nginx測試命令:nginx -t
查看uwsgi進程:ps -aux | grep uwsgi 
正常關閉uwsgi進程:uwsgi --stop /home/mysite_uwsgi/master.pid 
強制關閉全部uwsgi進程:ps -aux | grep uwsgi |awk '{print $2}'|xargs kill -9 
重新加載uwsgi:uwsgi --reload /home/mysite_uwsgi/master.pid 

參考文檔: 
(Django官網)https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/uwsgi/ 
(uwsgi中文)https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/tutorials/Django_and_nginx.html 
(uwsgi英文)https://uwsgi.readthedocs.io/en/latest/tutorials/Django_and_nginx.html 
(自強學堂)https://code.ziqiangxuetang.com/django/django-nginx-deploy.html 

八、使用Nginx+Gunicorn部署(其他方案)

可參考:Centos上Python應用部署詳情(Nginx 和 Gunicorn 部署 Django項目)

九、配置清單(發布環境配置修改)

1、開發環境和生產環境配置分開
把原先的settings.py改名為settings_base.py,創建settings_development.py和settings_production.py文件。把基礎共用的配置保留在base文件里,在development文件里只保留Degbu、DATABASES等其他需單獨配置的設置,在production文件里同樣,development和production繼承base文件。注意配置不要重復

如果settings文件需要另起一個文件夾存放,比如放在mysite/settings下,那記得修改settings_base.py里的BASE_DIR設置

同時修改manage.py文件里的配置路徑(開發環境):
修改wsgi.py文件里的配置路徑(生產環境):

2、修改生產環境的配置:秘鑰不明文顯示

  • 修改Debug為False
  • 重新生成SECRET_KEY秘鑰,并設置從環境變量里讀取的方式獲取(不在配置文件里明文顯示)
  • 數據庫密碼也一樣,從環境變量里讀取的方式獲取(不在配置文件里明文顯示)
  • 郵箱的授權碼也一樣設置
# 重新生成秘鑰方法
from django.core.management import utils
utils.get_random_secret_key()  # 該方法可以生成秘鑰

# linux里設置環境變量
vim /etc/profile 
# 在文件最后面加上配置(如下圖)
# 然后生效
source /etc/profile

3、修改生產環境的配置:增加日志文件配置(官方文檔說明)
在settings_production.py文件最后增加日志配置

# 日志配置,若需要其他設置,可參考官方文檔
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': ‘/home/mysite_debug.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

在服務器上創建并修改mysite_debug.log文件的權限

chmod 666 mysite_debug.log

4、修改生產環境的配置:更改郵件設置的端口和認證方式
有些云服務器對25端口有嚴格的限制,所以我們把端口和認證方式改成SSL的:

# 端口改成465,記得在服務器上把465端口開放
EMAIL_PORT = 465
# EMAIL_USE_TLS 改成 EMAIL_USE_SSL
EMAIL_USE_SSL = True

5、增加404、500錯誤頁面
把404.html和500.html等文件放到templates根目錄下即可

6、增加favicon.ico圖標(瀏覽器圖標)

  • 第一種方法(這種方法可行):
    把favicon.ico圖標放到項目misite目錄下(目錄可以自定),然后同步到GITHUB,服務器pull同步數據
    編輯nginx配置文件(vim /home/myconfs/mysite_nginx.conf):
location /favicon.ico  {
        # 你的favicon.ico文件path
        alias /home/mysite/mysite/favicon.ico;
    }
  • 第二種方法(這個方法我在開發環境可以,部署到生產環境還是不行):
    把favicon.ico文件放到根目錄的static目錄下,然后修改urls.py,如下
from django.contrib.staticfiles.views import serve

urlpatterns = [
 ...
 path('favicon.ico', serve, {'path': 'favicon.ico'}),
]
  • 第三種方法(這種方法可以用,但admin管理界面里默認是沒有這個文件的)
# 修改base.html文件,在head里增加讀取favicon.ico
<link href="{%static "favicon.ico" %}" rel="shortcut icon"/>

7、設置上傳文件目錄的權限

# 修改media目錄的權限
chmod 777 media/

8、重新匯聚靜態文件

python3 manage.py collectstatic

9、重啟nginx和uwsgi測試

十、正常運行后發現的問題記錄和處理

1、django-ckeditor插件里上傳圖片是報server 500錯誤
解決方法:網上有說把media文件夾權限改成777,但我不行,我把/usr/local/nginx/conf/nginx.conf配置文件里第一行原值#user nobody; 修改為 user root;并保存。使用 /usr/local/nginx/sbin/nginx -s reload 命令重新加載配置文件即可。


但我不想用root,但試了改成nginx用戶等都不行,暫時沒有找到其他辦法。
2、我們在頁面編輯的時候,總是要寫代碼的,但現在的django-ckeditor插件還沒有設置插入代碼的功能
解決方法:在settings設置里,修改CKEDITOR_CONFIGS的設置:

CKEDITOR_CONFIGS = {
    'default': {
        'width': 'auto',
        'toolbar': (
            ['div', 'Source', '-', 'Preview'],
            ['Copy', 'Cut', 'Paste', 'PasteText', 'PasteFromWord',],
            ['Undo', 'Redo', '-', 'Find', 'Replace', '-', 'SelectAll', 'RemoveFormat'],
            ['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript'],
            ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote'],
            ['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
            ['Link', 'Unlink', 'Anchor'],
            ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak'],
            ['Styles', 'Format', 'Font', 'FontSize'],
            ['TextColor', 'BGColor'],
            ['Maximize', 'ShowBlocks', '-', 'About'],
            ['CodeSnippet', '-', 'Print'],
        ),

        # 插件
        'extraPlugins': ','.join(['codesnippet', 'prism', 'widget', 'lineutils', ]),
    },
}

# 其中插件codesnippet既是代碼編輯功能,記得在toolbar里加上'CodeSnippet’按鈕
# prism為代碼高亮插件

3、加了codesnippet后,可以編輯代碼了,但當非編輯狀態下看的時候,發現代碼沒有高亮顯示,不美觀
解決方法:增加prism插件(詳細步驟可見這篇文章).

  • 從ckeditor官網下載 插件prism(點這里直接下載),然后將其解壓到ckeditor/static/ckeditor/ckeditor/plugins路徑下,同樣的我們需要在CKEDITOR_CONFIGS里將extraPlugins對應的value里加入插件 'prism' 和另外兩個插件"lineutils"、"widget" ,這兩個插件無須下載,在django-ckeditor中已經有了.

  • 去prismjs官網下載css文件http://prismjs.com/download.html,選擇你喜歡的主題,勾選支持的語言,以及別忘選擇line-numbers功能,下載后把他解壓到自己項目的static/下

  • 然后在模板中引用靜態文件即可

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容