先說說他們的關係,Nginx和uWSGI都是Web伺服器,Nginx負責靜態內容,uWSGI負責Python這樣的動態內容,二者配合共同提供Web服務以實現提高效率和負載均衡等目的。uWSGI實現了多個協議,如WSGI,HTTP協議,還有它自己的uwsgi協議,想瞭解更多關於uWSGI和uwsgi協... ...
先說說他們的關係,Nginx和uWSGI都是Web伺服器,Nginx負責靜態內容,uWSGI負責Python這樣的動態內容,二者配合共同提供Web服務以實現提高效率和負載均衡等目的。uWSGI實現了多個協議,如WSGI,HTTP協議,還有它自己的uwsgi協議,想瞭解更多關於uWSGI和uwsgi協議內容可以查閱這裡。這樣和fastcgi類似,請求和響應的流程如下:
Request > Nginx > uWSGI > Django > uWSGI > Nginx > Response
請求先交由Nginx,如果是靜態內容就自己處理了,如果是動態內容就交給uWSGI伺服器,uWSGI伺服器處理整個Django項目的Python代碼,響應請求,原路返回,但是與fastcgi不同,Nginx、uWSGI和Django可以獨立部署,然後整合。那麼我們從Django開始,這裡的伺服器環境是Ubuntu 16.10。
1. 部署Django的項目
安裝Python和Django,Ubuntu自帶2.7和3.5版本的Python,安裝相應的Django版本,註意在Ubuntu中不同版本Python都有相應的命令
www@cloud-vm-ub01:~$ python --version Python 2.7.12+ www@cloud-vm-ub01:~$ python3 --version Python 3.5.2+ www@cloud-vm-ub01:~$ pip -V pip 9.0.1 from /home/wisesoe/.local/lib/python2.7/site-packages (python 2.7) www@cloud-vm-ub01:~$ pip3 -V pip 9.0.1 from /home/wisesoe/.local/lib/python3.5/site-packages (python 3.5) pip3 install django
將已經完成開發的Django項目pro(pro是Django項目名)拷貝到伺服器,這裡拷貝到了www用戶(www是伺服器可登錄用戶名)路徑下,最後相對路徑是~/work/project/pro,絕對路徑是/home/www/project/pro
進入以上目錄,使用Django的內置伺服器測試看看pro項目是否運行正常。
python3 ./manage.py runserver 127.0.0.1:8080
2. 部署uWSGI伺服器
通過pip安裝uWSGI。
pip3 install uwsgi
測試uWSGI是否正常,在~/work/project/pro目錄中創建一個測試用的Python文件uwsgi_test.py
def application(env, start_response): start_response('200 OK',[('Content-Type', 'text/html')]) #return ['Hello world'] # Python2 return [b'Hello world'] # Python3
在pro項目路徑下,基於HTTP協議運行uWSGI,如果uWSGI安裝正常的話,可以在瀏覽器中訪問9090埠,看到Hello world字樣
uwsgi --http 127.0.0.1:9090 --wsgi-file uwsgi_test.py
接下來啟動uWSGI載入Django項目,這裡依然使用HTTP協議,將指向具體Python文件--wsgi-file參數替換為指向Django項目的--module參數,參數的值pro.wsgi指向~/work/project/pro/pro/wsgi.py模塊,如果正常可以在瀏覽器http://127.0.0.1:9090埠打開了項目,但是靜態文件路徑有問題,不過沒關係後面再處理。
www@cloud-vm-ub01:~/work/project/pro$ uwsgi --http 127.0.0.1:9090 --module pro.wsgi
對於uWSGI伺服器的配置,如上命令加上很多參數非常麻煩,可以寫成配置文件的方式,在~/work/project/pro中創建一個配置文件uwsgi.ini,註釋掉參數暫時忽略,Django 1.4以前的版本需要配置如env,pythonpath等參數,這裡不再深究了。
其中http參數用於以上測試,而與Nginx交互需要使用socket參數,即使用TCP協議,WSGI和uwsgi協議都在TCP協議之上。socket參數也可以配置為網路地址,如socket=127.0.0.1:7070,但如果Nginx和uWSGI同在一個伺服器上,可以使用socket文件的形式。chmod-socket是為了動態配置socket文件的許可權,因為socket文件會在每次uWSGI啟動時被重新創建。
[uwsgi] http=127.0.0.1:8000 #socket=/home/www/work/project/pro/nginx_uwsgi.socket chdir=/home/www/work/project/pro/ #chmod-socket=664 master=true processes=4 threads=2 module=pro.wsgi #wsgi-file=uwsgi_test.py #stats=127.0.0.1:9000
通過下麵命令同樣可以啟動uWSGI載入Djiango項目
uwsgi --ini uwsgi.ini
3. 部署Nginx伺服器
通過apt安裝Nginx
sudo apt install nginx
Nginx可以通過以下命令控制。正常安裝和啟動Nginx後,通過http://127.0.0.1:80可以看到Nginx的歡迎頁
sudo service nginx start sudo service nginx stop sudo service nginx restart
接下來修改配置Nginx配置與uWSGI伺服器交互。Nginx的主要配置文件在/etc/nginx/nginx.conf和sites-enabled文件夾里,nginx.conf是全局設置,sites-enabled文件夾里的可以針對不同站點進行配置,其中有個預設的default配置文件,該文件其實是sites-available文件夾里的default文件的軟鏈接,sites-avaliable像個倉庫,但只有sites-enabled里的才有效。我們可以將sites-enabled的default刪除,再cp一份sites-available的default到sites-enabled里重名為nginx-pro,同時cp /etc/nginx/uwsgi_params ~/work/project/pro里以備nginx-pro配置文件調用。
#nginx-pro
upstream django{ server unix:///home/wisesoe/Work/Project/Python/duty/nginx_uwsgi.sock; # file socket #server 127.0.0.1:7070; # TCP socket } server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name 127.0.0.1; # IP or FQDN location /static { alias /home/www/work/project/pro/static; } location / { uwsgi_pass django; include /home/www/work/project/pro/uwsgi_params; #try_files $uri $uri/ =404; } }
uwsgi_params文件是Nginx向uWSGI傳遞的參數,uwsgi_pass的意思動態內容請求都通過名為django的upstream傳遞給uWSGI,這使用文件socket的方式,那麼與之前uwsgi.ini里的socket參數配置一致。
4. Nginx許可權問題
以上全部配置完成了,但是還有一個重要的許可權問題,如果啟動uWSGI和Nginx(以下需要兩個終端視窗,因為uwsgi命令會占據一個),會報錯
uwsgi --ini uwsgi.ini sudo service nginx restart
在/var/log/nginx/error.log中會看到Permission denied字樣,是對home/www/work/project/pro/nginx_uwsgi.socket文件沒有讀寫許可權,即運行Nginx工作進程的用戶需要socket文件的讀寫許可權。
運行Nginx的工作進程的用戶在/etc/nginx/nginx.conf中有配置,是user的值www-data,但查看/etc/group發現www-data是個用戶組
user www-data; worker_processes auto; pid /run/nginx.pid; events { worker_connections 768; # multi_accept on; }
我們可以將www用戶加入該用戶組
usermod -G www-data www
也可以將socket文件及其上級目錄pro的用戶組改為www-data,併為該用戶組授予讀寫許可權
chown :www-data ~/home/work/project/pro chown :www-data ~/home/work/project/pro/nginx_uwsgi.socket chmod g+rw ~/home/work/project/pro/nginx_uwsgi.socket
5.Nginx和Django靜態文件處理
Django項目可以正常打開,但是靜態文件引用路徑還有問題,在Django開發時Django自己可以正確處理靜態文件的路徑,但是部署後Nginx去無法找到靜態文件路徑。
檢查Nginx配置文件夾sites-enabled里的nginx-pro文件,確保裡面預設的try_files要刪掉或者註釋掉,否則Nginx會因此檢查靜態文件是否存在。
將Django的靜態文件集中起來,Django為此有專門的工具
現在Django的Settings文件中加上StATIC_ROOT,把靜態文件都集中到這個路徑下
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
執行命令
python3 ./manage.py collectstatic
這樣所有Django前後臺的靜態文件都會集中到項目文件夾pro下static中,另外nginx-pro其中一個配置location /static即可讓Nginx來處理靜態內容。