Nginx+uWSGI+Django 配置

前言

       我们在使用 Django 开发的时,测试过程中通常使用 Django 自带的 web 服务器,并设置 Debug=False,这样可以实时修改代码并更新程序。但是在生产环境中通常使用 Nginx+uWSGI+Django 这样的模式。

       在这种模式中,使用 Nginx 作为最前端 web 服务器,它接收所有请求并统一管理所有请求。然后 Nginx 将所有的非静态请求通过 uWSGI发送给 Django 处理,Django 处理返回结果由 uWSGI 发给 Nginx,并返回给用户。可见,uWSGI的作用就类似一个桥接器。起到桥梁的作用。

不使用Nginx,只使用uWSGI+Django也是可以实现WEB服务的。uWSGI也可以直接处理WEB请求

uwsgi、uWSGI、WSGI的区别

WSGI

WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。

       WSGI 的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。

       WSGI 是作为 Web 服务器与 Web 应用程序或应用框架之间的一种低级别的接口,以提升可移植 Web 应用开发的共同点。WSGI 是基于现存的 CGI 标准而设计的。

       
很多框架都自带了 WSGI server ,比如 Flask,webpy,Django、CherryPy等等。当然性能都不好,自带的 web server 更多的是测试用途,发布时则使用生产环境的 WSGI server或者是联合 Nginx 做 uwsgi 。

也就是说,WSGI就像是一座桥梁,一边连着web服务器,另一边连着用户的应用。但是呢,这个桥的功能很弱,有时候还需要别的桥来帮忙才能进行处理。WSGI 的作用如图所示:

WSGI 的作用

WSGI的作用

       
WSGI有两方:“服务器”或“网关”一方,以及“应用程序”或“应用框架”一方。服务方调用应用方,提供环境信息,以及一个回调函数(提供给应用程序用来将消息头传递给服务器方),并接收Web内容作为返回值。

       
所谓的 WSGI中间件同时实现了API的两方,因此可以在WSGI服务和WSGI应用之间起调解作用:从WSGI服务器的角度来说,中间件扮演应用程序,而从应用程序的角度来说,中间件扮演服务器。“中间件”组件可以执行以下功能:

       
重写环境变量后,根据目标URL,将请求消息路由到不同的应用对象。
允许在一个进程中同时运行多个应用程序或应用框架。
负载均衡和远程处理,通过在网络上转发请求和响应消息。
进行内容后处理,例如应用XSLT样式表。
WSGI 的设计确实参考了 Java 的 servlet。python 开发者文档中有这么一段话:

By contrast, although Java has just as many web application frameworks available, Java’s “servlet” API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API.

uWSGI 和 uwsgi

       uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

       要注意 WSGI / uwsgi / uWSGI 这三个概念的区分。

  • WSGI看过前面小节的同学很清楚了,是一种通信协议。
  • uwsgi同WSGI一样是一种通信协议。
  • 而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。

       uwsgi协议是一个uWSGI服务器自有的协议,它用于定义传输信息的类型(type of information),每一个uwsgi packet前4byte为传输信息类型描述,它与WSGI相比是两样东西。

       关于uwsgi协议看这里:The uwsgi protocol。

       为什么有了uWSGI为什么还需要Nginx?因为Nginx具备优秀的静态内容处理能力,然后将动态内容转发给uWSGI服务器,这样可以达到很好的客户端响应。

uWSGI+Django

###安装

uWSGI 的安装很简单:

1
pip install uwsgi

现在我们试下将 Django 跑起来。我们先在 virtualenv 创建一个 Django Project:

1
2
3
[root@nowamagic ~]# cd nowamagic_venv
[root@nowamagic nowamagic_venv]# source bin/activate
(nowamagic_venv)[root@nowamagic nowamagic_venv]# django-admin.py startproject nowamagic_pj

virtualenv 的路径与目录文件如下:

virtualenv 的路径与目录文件

Django Project 的路径与目录文件如下:

Django Project 的路径与目录文件

测试uwsgi

在你的服务器上写一个test.py:

1
2
3
4
5
# test.py

def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return "Hello World"

我的 test.py 的路径是 /root/nowamagic_venv/nowamagic_pj/test.py,执行以下命令:

1
2
3
[root@nowamagic ~]# cd nowamagic_venv
[root@nowamagic nowamagic_venv]# source bin/activate
(nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8001 --wsgi-file /root/nowamagic_venv/nowamagic_pj/test.py

访问网页 http://115.28.0.89:8001/,OK,显示 Hello World,说明 uwsgi 安装成功。

测试你的 Django 项目

前面我们用 django-admin.py startproject nowamagic_pj 创建了一个项目,现在我们用 Django 自带的 Web 服务器看看我们的项目有没出问题。还是进入我们虚拟环境:

1
2
3
[root@nowamagic ~]# cd nowamagic_venv
[root@nowamagic nowamagic_venv]# source bin/activate
(nowamagic_venv)[root@nowamagic nowamagic_venv]# python2.7 /root/nowamagic_venv/nowamagic_pj/manage.py runserver 0.0.0.0:8002

OK,启动 Django 自带的服务器了,我们再访问 http://115.28.0.89:8002/,成功显示:

正确显示

说明 Djanggo 项目也没问题。

连接Django和uwsgi

最后一步了,我们要把uwsgi与Django连接起来。

编写django_wsgi.py文件,将其放在与文件manage.py同一个目录下。我的放在 /root/nowamagic_venv/nowamagic_pj/ 下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python

# coding: utf-8

import os
import sys

# 将系统的编码设置为UTF8
reload(sys)
sys.setdefaultencoding('utf8')

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nowamagic_pj.settings")
from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()

注意不要直接 copy,有个地方要改:注意到语句os.environ.setdefault。比如我的项目为nowamagic_pj,则语句应该是 os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “nowamagic_pj.settings”)

OK,进入虚拟环境执行指令:

1
2
3
[root@nowamagic ~]# cd nowamagic_venv
[root@nowamagic nowamagic_venv]# source bin/activate
(nowamagic_venv)[root@nowamagic nowamagic_venv]# uwsgi --http :8000 --chdir /root/nowamagic_venv/nowamagic_pj/ --module django_wsgi

成功显示 Django It Works 页面。

这样,你就可以在浏览器中访问你的Django程序了。所有的请求都是经过uwsgi传递给Django程序的。

这里我们介绍了如何把uwsgi与Django连接起来。

Nginx+uWSGI+Django

先安装 Nginx,可以直接用 apt-get 安装

Nginx 配置

在 nginx.conf 上加入/修改,我的 server 配置如下(一切从简……):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 80;
server_name 115.28.0.89;
#server_name localhost;
access_log /home/nowamagic/logs/access.log;
error_log /home/nowamagic/logs/error.log;
#root /root/nowamagic_venv/nowamagic_pj;
location / {
uwsgi_pass 127.0.0.1:8077;
#include uwsgi_params;
include /etc/nginx/uwsgi_params;
#uwsgi_pass 127.0.0.1:8077;
#uwsgi_param UWSGI_SCRIPT index;
#uwsgi_param UWSGI_PYHOME $document_root;
#uwsgi_param UWSGI_CHDIR $document_root;
}
access_log off;
}

注意保证配置里写的目录 /home/nowamagic/logs/ 和 /home/nowamagic/logs/ 存在,接下来就没啥问题了,Nginx 配置很简单。

uWSGI 配置

前面我们是直接使用命令行来启动 uWSGI,在实际部署环境中,我们常用的是配置文件的方式,而非命令行的方式。

我的 Django 程序目录:/root/nowamagic_venv/nowamagic_pj/

这里让 Nginx 采用 8077 端口与 uWSGI 通讯,请确保此端口没有被其它程序采用。

uWSGI 支持多种配置文件格式,比如 xml,ini,json 等等都可以。

xml 配置

请确定你在上一节中的django_wsgi.py文件已经存在了。新建一个XML文件:nowamagic_pj.xml,将它放在 /root/nowamagic_venv/nowamagic_pj 目录下

1
2
3
4
5
6
7
8
9
10
<uwsgi>
<socket>127.0.0.1:8077</socket>
<listen>80</listen>
<master>true</master>
<pythonpath>/root/nowamagic_venv/nowamagic_pj</pythonpath>
<processes>1</processes>
<logdate>true</logdate>
<daemonize>/var/log/uwsgi.log</daemonize>
<plugins>python</plugins>
</uwsgi>

然后执行命令:

1
uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml

or

1
/usr/local/bin/uwsgi -x /root/nowamagic_venv/nowamagic_pj/nowamagic_pj.xml

加载指定的xml配置文件。当使用命令行参数时,可以使用简化命令“-x”。当然也可以不简写:

1
uwsgi --xml /etc/nowamagic.xml

甚至如果在命令行的最后一个参数以“.xml”结尾,那么就隐含将加载该xml文件作为配置。

1
uwsgi /etc/nowamagic.xml

有时候因各种环境问题,-x --xml 命令识别不了,可以使用下面的 ini 配置方式:

ini 配置

1
2
3
4
5
6
7
8
9
10
[uwsgi]
vhost = false
plugins = python
socket = 127.0.0.1:8077
master = true
enable-threads = true
workers = 1
wsgi-file = /root/nowamagic_venv/nowamagic_pj/nowamagic_pj/wsgi.py
virtualenv = /root/nowamagic_venv
chdir = /root/nowamagic_venv/nowamagic_pj

然后执行命令:

1
uwsgi --ini /root/nowamagic_venv/nowamagic_pj.ini & uwsgi

这样就启动起来了。如果无意外的话,就能在网上访问你的 Python 项目了。

一些我在配置时用到的命令,省得你去搜索:

  1. 关闭 uWSGI:

    1
    2
    3
    killall  -9 uwsgi
    killall -s HUP /var/www/uwsgi
    killall -s HUP /usr/local/bin/uwsgi
  2. 列出端口占用情况:

    1
    netstat -lpnt