主要内容来自于
https://uwsgi.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
系统情况:
Ubuntu 14.04.2 LTS (实际是麒麟版)
python3 version 3.5.2(源上直接apt-get)
pip3 version 8.1.1(源上直接apt-get)
若无特殊指代,localhost即为127.0.0.1
虽说本文类别定为“翻译”,但是并没有将上述链接所代表的网页直接翻译,而是取得其中的关键步骤,另加自己的细节调整。
我对virtualenv的理解非常浅,目前就理解为一种处理python多版本问题的“沙盒”解决方案,把想使用的python版本和对应的工具放到一个位置,不必担心系统层面的冲突。
实际安装时,使用
sudo pip3 install virtualenv
我目前理解激活(activate)virtualenv指创建一个virutalenv环境。由于我将使用python3,而在Ubuntu14中,系统的默认的python是2.7,那么在激活前的创建过程中需要指定所使用的python。在创建的同时需要指定一个virtualenv名称,virtualenv会创建相应的文件夹。实际创建virtualenv时使用如下命令
virtualenv -p /usr/bin/python3 uwsgi-tutorial
uwsgi-tutorial即指的是virtualenv名称,是沿用原网页上的描述。上述命令是我搜索得到的,原网页位置为stackoverflow。命令执行之后,会在当前文件夹下生成uwsgi-tutorial文件夹,进入该文件夹,那么我们现在所在位置为
/home/yaoyu/MySites/uwsgi-tutorial
其中yaoyu是我的用户名,MySites是我用来存放网站文件的位置(我就都不遮盖了。。)
此时,运行脚本bin/activate(该脚本位于/home/yaoyu/MySites/uwsgi-tutorial/bin)以激活该virtualenv
source bin/activate
pip install ipython
hash -r
成功激活后,终端的prompt会在最前面加上当前virtualenv的描述。上述第三条命令是令virtualenv重建对ipython的索引。参考这里。
安装Django,并创建一个示例project。
pip install Django
django-admin.py startproject mysite
cd mysite
mysite即为Django的project名,并且也是文件夹名(当然mysite下面还有一个mysite)。此时,我们的位置变为
/home/yaoyu/MySites/uwsgi-tutorial/mysite
可以现在立即测试Django project的可用性,并同时测一下端口的可用性。
python manage.py runserver 0:8000
若正常启动,则通过浏览器访问localhost:8000应能看到Django的信息。此时使用的是Django自带的development server,终端中用Ctrl+C终止Django的development server的运行。
安装uWSGI(在CenOS中可能需要先安装python3x-devel,3x代表版本号)
pip install uWSGI
为了简单测试uWSGI,编写test.py文件。当前我们仍位于
/home/yaoyu/MySites/uwsgi-tutorial/mysite
新建的test.py文件内容为
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"] # python3
测试uWSGI的有效性
uwsgi --http :8000 --wsgi-file test.py
此时若正常启动uwsgi,那么通过浏览器访问localhost:8000即可看到Hello Word字样。Ctrl+C 终止uwsgi。
之后可测试uWSGI与刚刚建立的Django project的数据交换。
uwsgi --http :8000 --module mysite.wsgi
我们当前仍在/home/yaoyu/MySites/uwsgi-tutorial/mysite,module wsgi即保存在
/home/yaoyu/MySites/uwsgi-tutorial/mysite/mysite/wsgi.py
此时利用浏览器访问localhost:8000应当可以看到Django的信息。
从源上直接安装nginx。
sudo apt-get install nginx
安装完毕后,启动nginx。
sudo /etc/init.d/nginx start
此时,使用浏览器访问localhost:80(注意端口,也可以不带端口),应当可以看见nginx的欢迎信息。
为了与uWSGI连接,需要一个uwsgi_params文件和一个nginx的conf文件。uwsgi_params文件可以从如下地址获取。
https://github.com/nginx/nginx/blob/master/conf/uwsgi_params
其内容为
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
将该uwsgi_params文件复制到Django project的文件夹,即
/home/yaoyu/MySites/uwsgi-tutorial/mysite
并在同样位置创建mysite_nginx.conf文件,内容为
# mysite_nginx.conf
# the upstream component nginx needs to connect to
upstream django {
# server unix:///home/yaoyu/MySites/uwsgi_tutorial/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 /home/yaoyu/MySites/uwsgi-tutorial/mysite/media; # your Django project's media files - amend as required
}
location /static {
alias /home/yaoyu/MySites/uwsgi-tutorial/mysite/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/yaoyu/MySites/uwsgi-tutorial/mysite/uwsgi_params; # the uwsgi_params file you installed
}
}
mysite_nginx.conf文件的内容包括上游数据源的描述,目前为localhost:8001,nginx监听8000端口向client提供web服务,server的media文件位置以及static文件位置,最后是这个server的根位置。将mysite_nginx.conf以符号连接的形式插入到nginx的默认服务器列表里。
sudo ln -s /home/yaoyu/MySites/uwsgi-tutorial/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/
收集Django project的static文件。修改/home/yaoyu/MySites/uwsgi-tutorial/mysite/mysite/settings.py,添加如下一行
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
然后执行
python manage.py collectstatic
将自动生成一个新文件夹static。启动nginx进行测试
sudo /etc/init.d/nginx restart
此时由于没有任何实际server在运行,于是访问localhost:8000是显示Bad Geteway。但是仍可以测试nginx的运行。在
/home/yaoyu/MySites/uwsgi-tutorial/mysite
下新建media文件夹,进入media文件夹,并复制一个png图片进来,然后利用localhost:8000/media/文件名.png的形式通过浏览器查看这个图片,若成功显示图片,代表nginx的配置是正确的。
首先通过uwsgi和test.py还有nginx进行联调。在
/home/yaoyu/MySites/uwsgi-tutorial/mysite
运行
uwsgi --socket :8001 --wsgi-file test.py
此时通过浏览器访问localhost:8000,此时应有Hello world字样。uwsgi通过localhost的8001端口向nginx提供数据,nginx再通过localhost的8000端口向浏览器提供数据。用Ctrl+C退出uwsgi。
现在利用Unix socket代替TCP端口。上面的测试使用的是8001端口,通过修改mysite_nginx.conf中upstream django中的描述(即将原来注释掉的socket描述恢复,而注释8001端口的描述。)再重启nginx服务
sudo /etc/init.d/nginx restart
另外,在Ubuntu系统上,nginx服务是默认已www-data用户和www-data用户组启动的。这里可以将当前用户添加至www-data用户组
sudo usermod -a -G www-data yaoyu
可能需要重新登录。之后可利用group或者id命令查看。
启动uwsgi
uwsgi --socket mysite.sock --wsgi-file test.py --chmod-socket=664 --chown-socket=yaoyu:www-data
推荐此时再另开一个Terminal,并输出nginx的error log
tail -f /var/log/nginx/error.log
通过浏览器访问localhost:8000,此时若出现Bad Gateway错误,并且nginx的error log提示Permission denied或connection refused。这表示nginx没有对mysite.sock文件的操作权限(仅限Ubuntu系统,对于CentOS或者Fedora可能是与SELinux有关)。处理方案是采用tmpfiles.d,可参考
https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
方案原理是将socket文件放置在一个nginx和uWSGI都有足够权限的位置,比较理想的位置是/run(或者其变种/var/run),在/run下建立一个文件夹位置,并设定该文件夹的权限。具体做法是在/etc/tmpfiles.d下新建一个conf文件,这里我们用mysite-socket.conf命名,其内容为
# Create directory for my sites.
d /run/mysite-socket 0775 www-data www-data -
这表示建立/run/mysite-socket 文件夹,并设定好权限位以及所有者和所有群,并不设定过期清空时间。
然后,修改mysite_uwsgi.conf的描述,将socket文件指向于/run/mysite-socket文件夹内。重启计算机。之后查看/run的内部是否有mysite-socket文件夹,并确认它的权限位和所有者情况。
调试成功后进行Django的联调。通过Ctrl+C退出uWSGI,在
/home/yaoyu/MySites/uwsgi-tutorial/mysite
重新启动uWSGI
uwsgi --socket /run/mysite-socket/mysite.sock --module mysite.wsgi --chmod-socket=664 --chown-socket=yaoyu:www-data
在浏览器中访问localhost:8000应当可以看到Django的信息。用Ctrl+C退出uWSGI。
为了避免使用命令启动uWSGI并实现自动化启动uWSGI,编写uWSGI的ini文件。命名为mysite_uwsgi.ini
# mysite_uwsgi.ini file
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /home/yaoyu/MySites/uwsgi-tutorial/mysite
# Django's wsgi file
module = mysite.wsgi
# the virtualenv (full path)
home = /home/yaoyu/MySites/uwsgi-tutorial
# process-related settings
# master
master = true
# maximum number of worker processes
processes = 10
# the socket (use the full path to be safe
socket = /home/yaoyu/MySites/uwsgi-tutorial/mysite/mysite.sock
# ... with appropriate permissions - may be needed
chmod-socket = 664
chown-socket = yaoyu:www-data
# clear environment on exit
vacuum = true
使用ini文件启动uWSGI
uwsgi --ini mysite_uwsgi.ini
同样通过浏览器访问localhost:8000,成功后终止uWSGI。
为了能够部署服务器,uWSGI不能仅运行在virtualenv中,需要在其外也能够正常运行。
以上的调试工作实际上完全在uwsgi-tutorial virtualenv中进行的,现在退出该virtualenv。执行
deactivate
安装uWSGI
sudo pip3 install uwsgi
安装完毕后,在
/home/yaoyu/MySites/uwsgi-tutorial/mysite
下测试uWSGI
uwsgi --ini mysite_uwsgi.ini
通过浏览器访问localhost:8000,应看到Django信息。用Ctrl+C退出uWSGI。
运行于emperor mode下的uWSGI,可以通过监视conf文件的变化,重新启动服务。emperor mode需要使用uWSGI的vassal文件夹进行配置,新建
/etc/uwsgi/vassals (需要root权限)
在该文件夹下添加符号连接
sudo ln -s /home/yaoyu/MySites/uwsgi-tutorial/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/
以emperor mode启动uWSGI
sudo uwsgi --emperor /etc/uwsgi/vassals --uid yaoyu --gid www-data
利用浏览器访问localhost:8000,应可看到Django信息。利用Ctrl+C退出uWSGI(emperor mode)。
配置/etc/rc.local文件(需要root权限),将上述uWSGI的emperor mode启动命令添加到rc.local文件的exit 0前。(貌似不加uid和gid也可以。)
/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --uid yaoyu --gid www-data --daemonize /var/log/uwsgi-emperor.log
保存文件,重新启动系统。重新启动之后,直接通过浏览器访问localhost:8000,应当可以看到Django信息。
多看官方网页,多用google,耐心不要急。初期尽量使用源,而不要自己编译python3什么的,别说我没提醒过。。。