Django web app 使用 uWSGI、Nginx 部署

2015-02-08

Django 入门是挺简单的,这个框架把很多东西都给做好了在里面,但想要理解这个运作原理还是没那么简单的,有的东西刚开始也用不着,到后面要是应用需要的功能越来越多就要用到框架里更多组件了。前段时间刚好看到有人 Gitbook 上放了一个 Django 搭建简单 Blog 的一个教程,我就照着做了一下,发现错误挺多,还有的地方根本没讲清楚,框架包办很多事情但也不是这么简单吧,但也学到了一些之前不知道的框架里内置的很方便快捷的功能。我自己照着做了,然后基本还行,就是分类功能还有问题,我自己还要加个时间的功能,还有 RSS 订阅 我也没有搞定,不知道是怎么回事,但基本功能没问题,Markdown 写作,然后复制到后台里面就行了,我就准备放到 Linode 上了,虽然没有域名,先用 IP 凑合凑合,等功能完善了再买域名。

0. 原理

Nginx 作为服务器最前端,接受所有请求,静态请求,媒体文件由 Nginx 处理,非静态请求由 uWSGI 传递给 Django 处理。

1. 安装 Nginx

1
2
sudo apt-get install nginx
sudo /etc/init.d/nginx start

还有其他的用法Usage: nginx {start|stop|restart|reload|force-reload|status|configtest},后面每次修改站点的ngnix 配置文件都需要reload

2. 安装 uWSGI

1
2
sudo apt-get install python-dev
pip install uwsgi

我也不知道前面的 python-dev 是干嘛的,但看别人说要不装就有可能要出错。 还有最后配置文件写在 XML 里面,还要装个 libxml

1
sudo apt-get install libxml2-dev

3. 测试 Django 应用是否能直接运行并更改为部署配置

整个项目放到服务器上,python manage.py runserver 0.0.0.0:8000,在8000 这个端口上打开试试,运行没有问题就把项目里的settings.py开发配置改成部署配置。

1
2
3
4
5
6
7
DEBUG = FALSE
ALLOWED_HOSTS = ["*"]

STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
) # 删掉这个配置项

这个地方要把 STATICFILES_DIRS 删掉改成 STATIC_ROOT = "/home/chen/DjangoProjects/static", 然后在执行 python manage.py collectstatic, 这一步会把一些静态文件全复制到项目的静态文件夹下,这个步骤如果不执行的话就会发现部署上去后台是看不到样式的。

4. 测试 uWSGI

在项目下面新建test.py

1
2
3
4
# test.py
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return "Hello World"

uwsgi --http :8000 --wsgi-file test.py,在 8000 端口打开试试,能出现 Hello World 就没问题,这个地方由可能回出现一个 libpcrePCRE-8.36 的问题,要自己下回来编译装上就行了。

5. my_blog_wsgi.py uWSGI 配置文件

这个地方要是直接照抄各种中文博客到最后肯定都跑不起来,因为他们的 Django 版本太老了,这个地方还是查 stackoverflow 改了就整个跑起来了,Django 1.7 throws django.core.exceptions.AppRegistryNotReady: Models aren’t loaded yet

1
2
3
4
5
6
7
8
9
10
11
# my_blog_wsgi.py
import os
import sys

reload(sys)
sys.setdefaultencoding('utf8')

from django.core.wsgi import get_wsgi_application # Django 1.7 前是 from django.core.handlers.wsgi import WSGIHandler

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_blog.settings") # “你的项目.settings”
application = get_wsgi_application() # 1.7以前是 application = WSGIHandler()

6. 配置 Nginx

首先由一个文件要复制到项目下面 可以从这里复制粘贴 nginx/conf/uwsgi_params,也可以从 /etc/nginx 里复制过去,可能权限要改下,还是直接自己 vi 粘贴比较好。

第二步是站点的 nginx 配置文件,刚开始我照着别人的做,把这个文件放在自己的项目下,然后软连接上去,结果看 log 说我没有这个文件,然后在放到/etc/nginx/sites-enabled 才行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# my_blog__nginx.conf

server {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name XXX.XXX.XXX.XXX; # substitute your machine's IP address or FQDN
charset utf-8;

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

# logs
access_log /home/chen/DjangoProjects/my_blog/logs/access.log;
error_log /home/chen/DjangoProjects/my_blog/logs/error.log;

# Django media
location /media {
alias /home/chen/DjangoProjects/my_blog/media; # your Django project's media files - amend as required
}

location /static {
alias /home/chen/DjangoProjects/my_blog/static; # your Django project's static files - amend as required
}

# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass XXX.XXX.XXX:8001;
include /home/chen/DjangoProjects/my_blog/uwsgi_params; # the uwsgi_params file you installed
}
}

首页就在 8000 这个端口上,server_name 是 VPS 的 IP,logs 文件夹要自己创建,哪都行,/media /static 两个文件夹是静态请求,由 nginx 处理,其他非静态请求由 uwsgi_pass 通过 socket 传递给 Django 处理,用的 8001 端口,include 就是复制的那个文件,放在项目下。

7. my_blog_socket.xml XML 配置文件

1
2
3
4
5
6
7
<uwsgi>
<socket>XXX.XXX.XXX.XXX:8001</socket>
<chdir>/home/chen/DjangoProjects/my_blog</chdir>
<module>my_blog_wsgi</module>
<processes>4</processes>
<daemonize>/home/chen/DjangoProjects/my_blog/uwsgi.log</daemonize>
</uwsgi>

socket 就是刚才my_blog_bginx.conf 里面的uwsgi_pass通过socket 传递过来,chdir 是项目文件夹,modulemy_blog_wsgi.py wsgi 配置文件,processes nginx 分配四个线程,daemonize 是日志文件,要是配置不成功,错误信息都在里面,什么 libpcre 库没有啊,没有 app load 起来啊。

8. 最后一步

1
2
sudo /etc/init.d/nginx reload
uwsgi -x my_blog_socket.xml

reload 一下 nginx 的配置文件,然后用 xml 配置把 uwsgi 把应用挂起来,提示 [uWSGI] parsing config file my_blog_socket.xml,然后到 ip:8000 端口下看成不成功,不成功的话到项目的uwsgi.log 最后面看,错误信息都在里面,然后去查。

9. 参考链接