Django + Nginx + uWSGI 部署

英文原文请参照此文:Setting up Django and your web server with uWSGI and nginx。我只是稍微翻译并总结了一下。

转发请注明出处:Django + Nginx + uWSGI 部署

对于 Django 部署来说,选择 Nginx 和 uWSGI 是一个不错的选择,此教程旨在将 Django 部署到生产环境的服务器中。当然你也可以使用 Apache 或者其他的服务器部署方式,不过笔者看来,用 uWSGI 还是相对简单的。

概念

Web Server 是面向外界的。它可以提供文件服务,但并不能直接与 Django 应用通话;它需要一些东西来运行这个应用,将请求从客户端喂给它,并且返回响应。

Web Server Gateway Interface - WSGI - 就是用来做这件事的。WSGI 是一种 Python 标准。

uWSGI 是 WSGI 的一种实现。在此教程中,我们将创建 uWSGI,以让它创建一个 Unix socket,并且通过 WSGI 协议来服务于 web server 的响应。整个最后形式如下:

代码语言:javascript
复制
the web client <-> the web server <-> the socket <-> uwsgi <-> Django  

安装 uWSGI 之前

virtualenv

先确保拥有一个 python 虚拟环境:

代码语言:javascript
复制
virtualenv uwsgi-tutorial  
cd uwsgi-tutorial  
source bin/activate
安装 Django

将 Django 安装到你的虚拟环境中,创建一个新的 project,并 cd 到这个目录下:

代码语言:javascript
复制
pip install Django  
django-admin.py startproject mysite  
cd mysite
关于域和端口

在这篇教程中,我们将称你的域为 example.com,可以自行替换为你的IP。

通篇我们将使用 8000 端口来部署 web 服务,就如 Django 运行环境默认的一样。当然你也可以换成另外的端口,但注意不要与其他应用冲突。

基本的 uWSGI 安装和配置

在 virtualenv 中安装 uWSGI
代码语言:javascript
复制
pip install uwsgi  

注意在安装 uwsgi 之前请确保安装了 python 开发包,使用 Debian 系统的话,安装pythonX.Y-dev,X.Y 是 Python 的版本。

简单测试

创建一个文件 test.py:

代码语言:javascript
复制
# test.py
def application(env, start_response):  
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"] # python3
    #return ["Hello World"] # python2

运行 uWSGI:

代码语言:javascript
复制
uwsgi --http :8000 --wsgi-file test.py  

参数意义:

  • http :8000:使用 http 协议,8000 端口
  • wsgi-file test.py:载入特定文件, test.py

这应该直接在浏览器中返回 hello world。访问:

代码语言:javascript
复制
http://example.com:8000

以检查。如果如此,说明如下配置成功了:

代码语言:javascript
复制
the web client <-> uWSGI <-> Python  
测试你的 Django project

现在我们想让 uWSGI 做同样的是,但是是运行一个 Django 项目,而不是 test.py 模块。

如果你还未这样做过,请确保你的 mysite 项目运行正确:

代码语言:javascript
复制
python manage.py runserver 0.0.0.0:8000  

如果它成功了,使用 uWSGI 运行它:

代码语言:javascript
复制
uwsgi --http :8000 --module mysite.wsgi  
  • module mysite.wsgi:载入特定 wsgi 模块 在浏览器中访问你的服务器,如果出现了网站,说明 uWSGI 可以服务一个 Django 应用,在 virtualenv 中,如下:
代码语言:javascript
复制
the web client <-> uWSGI <-> Django  

现在一般我们不会让浏览器直接与 uWSGI 对话。这是 web server 的工作。

基本的 Nginx

安装 Nginx
代码语言:javascript
复制
sudo apt-get install nginx  
sudo /etc/init.d/nginx start    # start nginx  

安装完后检查 nginx 正在服务,访问 80 端口,你应该能得到一个 “Welcome to nginx!” 的返回。说明:

代码语言:javascript
复制
the web client <-> the web server  
为你的网站配置 Nginx

你需要 uwsgi_params 文件,访问 GitHub 下载。

复制到你的项目目录。之后我们会通知 Nginx 来引用它。

现在,创建一个文件叫做 mysite_nginx.conf,然后把这些放进去(可以复制 default 修改):

代码语言:javascript
复制
# mysite_nginx.conf

the upstream component nginx needs to connect to

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 {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name .example.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 /path/to/your/mysite/media;  # your Django project&#39;s media files - amend as required
}

location /static {
    alias /path/to/your/mysite/static; # your Django project&#39;s static files - amend as required
}

# Finally, send all non-media requests to the Django server.
location / {
    uwsgi_pass  django;
    include     /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
}

}

这一配置文件告诉 nginx 从文件系统为文件提供服务,以及处理需要 Django 的请求。

创建一个链接以让 nginx 发现它:

代码语言:javascript
复制
sudo ln -s ~/path/to/your/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/  
部署静态文件

在运行 nginx 之前,要把 Django 的静态文件集中到 static 文件夹中。首先你应该修改 mysite/settings.py 文件,添加:

代码语言:javascript
复制
STATIC_ROOT = os.path.join(BASE_DIR, "static/")  

然后执行:

代码语言:javascript
复制
python manage.py collectstatic  
基本nginx测试

重启 nginx

代码语言:javascript
复制
sudo /etc/init.d/nginx restart  

为确定 Media 文件被正确服务,添加一个图片文件 media.png/path/to/your/project/project/media directory 目录,然后访问 http://example.com/media/media.png。 如果成功,你将会知道至少 nginx 服务文件是正常的。

nginx 和 uWSGI 和 test.py

让我们让 Nginx 来与 “hello world” test.py 进行通话。

代码语言:javascript
复制
uwsgi --socket :8001 --wsgi-file test.py  

这几乎与之前的一样,除了参数不同

  • socket :8001:使用 uwsgi 协议,8001 端口 Nginx 同时配置完成了,以与 uWSGI 通信在 8001 端口通信,并在外部 8000 端口通信。访问:

http://example.com/

以检查。现在整个 stack 如下:

代码语言:javascript
复制
the web client <-> the web server <-> the socket <-> uWSGI <-> Python  

使用 Unix sockets 代替端口

使用 TCP 端口 socket 虽然简单,但是最好使用 Unix sockets 而不是端口。

编辑 mysite_nginx.conf

代码语言:javascript
复制
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)

重启 nginx。

重新运行 uWSGI:

代码语言:javascript
复制
uwsgi --socket mysite.sock --wsgi-file test.py  

Try http://example.com/ in the browser.

如果不起作用

检查 nginx 错误日志 (/var/log/nginx/error.log)。如果你看到如下:

代码语言:javascript
复制
connect() to unix:///path/to/your/mysite/mysite.sock failed (13: Permission

denied)

说明权限不够,尝试:

代码语言:javascript
复制
uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=666 # (very permissive)  

或者:

代码语言:javascript
复制
uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=664 # (more sensible)  

使用 uWSGI 和 Nginx 运行 Django 项目

现在运行 Django 项目:

代码语言:javascript
复制
uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=664  

现在 uwsgi 和 nginx 应该在服务你的 Django 应用,而不是 hello world。

配置 uWSGI 以使用 .ini 文件运行

可以将参数放在文件中,然后运行该文件以运行 uwsgi。

创建一个文件 mysite_uwsgi.ini

代码语言:javascript
复制
# mysite_uwsgi.ini file
[uwsgi]

Django-related settings

the base directory (full path)

chdir = /path/to/your/project

Django's wsgi file

module = project.wsgi

the virtualenv (full path)

home = /path/to/virtualenv

process-related settings

master

master = true

maximum number of worker processes

processes = 10

the socket (use the full path to be safe

socket = /path/to/your/project/mysite.sock

... with appropriate permissions - may be needed

chmod-socket = 664

clear environment on exit

vacuum = true

使用如下命令运行 uwsgi:

代码语言:javascript
复制
uwsgi --ini mysite_uwsgi.ini # the --ini option is used to specify a file  
附加

让 uwsgi 在后台运行:

代码语言:javascript
复制
uwsgi --ini mysite_uwsgi.ini --logto mysite.log &