环境:Centos7.5 或 Ubuntu16.04.6 如果配置中遇到了什么问题欢迎留言,随时修改博客中的问题,欢迎指正。我开启的80端口供nginx使用,8000端口供uwsgi使用。
框架:Django
说明:部分内容转载,特别感谢大佬的博客:https://blog.csdn.net/u012145252/article/details/82147440本文只是结合自身的实际情况做了一些记录,供学习使用。
正式将之前先说一下大概步骤,我们先将uwsgi与django服务配置好,再将nginx与uwsgi服务之间的联系给配置好,如果你在看这篇文章之前对于这三者的关系不太清楚的话也不要紧,耐心的看完你就明白了,现在开始之前,你只需要了解他们三者的这个配置顺序就行了。配置顺序不是固定的,本文以这种顺序进行配置,主要是为了方便调试与理解,现在我们开始!
一、 uWSGI部署
首先,需要在自己服务器中安装uwsgi,如果是在虚拟环境中使用,则安装在虚拟环境中,如果是直接配置在服务器上就直接安装:
pip3 install uwsgi
安装完成后可以使用uwsgi --version查看版本信息。
测试运行uWSGI
首先我们需要一个测试代码,来帮助我们走过测试这一关,以免直接使用庞大的网站源代码来配置。
在项目根目录创建一个test-uwsgi.py
,代码如下,请注意函数名,必须为application
,因为这是uwsgi服务默认通知Dajngo的接口。在我们自己经常使用的Django框架的wsgi.py
的配置文件中也能看到。
def application(env,start_response):
start_response('200 OK',[('Content-Type','text/html')])
return [b"Hello Hero, all for one "]
以下命令表示运行uwsgi服务,同样是在8000端口上开放web访问。
- 注意–http 后是一个空格再接:端口号。
uwsgi --http :8000 --wsgi-file test-uwsgi.py
访问web服务器8000端口,正常显示test-uwsgi.py脚本中返回显示的文本。
因为我们现在要做的是基于nginx和uwsgi部署django,从客户端发起请求到服务器响应请求,会经过一下几个环节:
the web client <-> the web server(nginx) <-> the socket <-> uwsgi <-> Django
而单独测试uWSGI运行,访问显示正常的话,说明下面3个环节是通畅的:
the web client <-> uWSGI <-> Python
ctrl+c中止程序,再来进行以下的测试。
使用uWSGI运行django项目
在虚拟环境下,进入到django根目录下后敲以下命令:
uwsgi --http :8000 --module projectname.wsgi
效果和直接敲以下命令
python manage.py runserver 0.0.0.0:8000
是一样的。
说明:以上的projectname.wsgi
是调用了项目根文件夹下的wsgi.py
的网关服务配置文件,默认情况下是不需要用户进行更改的。Django的项目文件夹路径我就不哆嗦了,学过都知道,查一下也就大概了解了。因此必须要在项目的根目录执行该命令。
注:–module projectname.wsgi为加载指定的wsgi模块,你项目起的是什么名字,一般就是项目名.wsgi。
这样测试下来,可证明web客户端通过uWSGI到Django是通畅的:
the web client <-> uWSGI <-> Django
ctrl+c中止程序,再来进行以下的测试
uWSGi热加载Djangoa项目
在启动命令后面加上参数:
uwsgi --http :8000 --module pojectname.wsgi --py-autoreload=1
同样,这个时候访问服务器8000端口,也就是访问了django项目(pojectname)。
而且还多了一个参数:
--py-autoreload
监控python模块以触发重载(仅在开发中使用)
类似的发布命令
/..dir../uwsgi --http 0.0.0.0 :8000 --chdir /home/operation/work/luffy --module luffy.wsgi`
#此时修改django代码,uWSGI会自动加载django程序,页面生效 # 除此外,还可以接上很多参数
uwsgi部署加强
一、 使用uwsgi配置文件运行django项目
上面的配置都是属于测试阶段,如果测试一遍没有问题后,我们就可以进行系统的配置了。uwsgi支持ini,xml等多种配置方式,以ini为例,在项目根目录下新建uwsgi.ini,示例配置如下:
[uwsgi] #代表这里是uwsgi的配置文件,必须要写这个在第一行
# 指定运行目录,其实就是项目的根目录
# 导入django项目的wsgi模块,我的项目叫GradingSystem,其中application就是默认的网关配置文件的那个函数
module = GradingSystem.wsgi:application
dir=/web/GradingSystem
# 载入wsgi-file,这里是指明网关配置文件在项目文件夹下的路径
wsgi-file = GradingSystem/wsgi.py
# 补充,uwsgi启动时的用户和用户组,注意要按你自己的实际权限进行配置
# 我这边是因为项目属主是gxa,而gxa我设置了添加进了gxa组
# 但这种情况下uid仍不能设置gxa,除非你的项目目录所有文件属主都改为了gxa
uid = centos
gid = www
# 开启master主进程
master = true
# 开启多少个进程数,workers项也等同processes
# threads项则是设置运行线程,测试倒不用设置上线程
processes = 10
# 设置使用的socket端口或socket地址
# socket = 0.0.0.0:8000
# 上面的socket建议配置成一个GradingSystem.socket文件后使用nginx来连接uWSGI运行,不然容易报socket的请求头错误和权限错误等。
#socket = /web/GradingSystem/GradingSystem.socket
#以上信息来源于转载,是大佬博主的建议,但是我采用之后出现了网关错误的问题,可能是我哪里没有搞明白,但是换成下面的配置后就正常了,这个socket指定的端口代表的是uwsgi服务监听的端口
# 在配置uwsgi时,如果直接使用socket进行配置,那么浏览器无法通过http协议进行访问,必须在前面加上nginx转发才可以通过nginx间接访问,因此只测试uwsgi时使用http进行配置。
#socket = 0.0.0.0:8000
http = 0.0.0.0:8000
# 配置生成的sock文件的权限,一般对网站用户的权限都设置为如此,较为安全
chmod-socket = 664
# 退出时清空环境,其实就是将自动生成的GradingSyster.sock和相关pid文件给干掉。
vacuum = true
#设置uwsgi服务的缓存区大小
auffer-size = 65536
uwsgi指定配置文件启动django项目,建议使用web指定的用户执行:
uwsgi --ini /..dir../uwsgi.ini
(其中…dir…是项目在服务器上的路径)
二、 配置网站的用户组问题
首先强调一下,根目录权限设置的必要性:
为了安全,以及网站服务器的运行,我们需要使用特定的用户和用户组,按照常规做法,我们就会选择使用www用户组下面的www用户来运行网站服务器,不论是nginx还是apache,我们都可以这么做。
www用户运行的服务器需要读取网站根目录的各种资源,包括动态脚本,比如php脚本,或者是html、css、javaScript等文件。当然了,我们也可以通过在php脚本中切换到其他的用户来执行特别的脚本,这点和在shell脚本中切换用户是一样的。
除此之外我们还可以新建一个自定义用户,新建一个自定义用户组,并将项目文件的所属设置为该用户组的该用户,并且设置相应的目录访问权限。
1、假如web服务器是apache,那么用户访问web页面的时候,就是通过apache服务(httpd)的所有者的身份进行访问,所以要将 apache也就是httpd服务的所有者和所有组设为apache或者自定用户,不要用root,这个一般安装的时候就会有默认设置(或者修改apache配置文件的User和Group项)。
2、网站程序的所有者不要和apache服务的所有者一样,如果一样就相当于给了普通访问者对web文件的所有操作权!一旦web程序有漏洞,那就
over了!默认一般是root,尽量改为其他用户,比如自己建立一个daemon,切记不要和apache服务的所有者一样。3、对于网站根目录权限,按照最小权限的原则,应设置为755
4、对于缓存目录或者上传目录例如缓存目录:caches目录,由于此目录必须要有写权限,也就是目录同是有rwx三个权限,这时候可以直接建立一个
caches空目录,然后chown daemon.daemon
./caches,就是把caches所有者、所有组改为自定义的daemon就ok了,这样如果访问web页面,就会以apache的身份进入
caches建立缓存目录及文件,默认系统都是以最小权限建立!5、对于普通目录,最小权限为755,普通用户不给写权限
6、对于普通文件,最小权限为644,普通用户不给执行权限
总而言之,言而总之就是:目录不要给写权限,文件不要给执行权限(除非特殊情况,如目录要上传)
以上是较为严格的网站目录权限设置,由于在我自己配置的时候,还没有查到这一条资料。因此我对权限的管理没有上面说的这么细致,但是操作的方法都是相同的。以下操作在root权限下执行
1. 创建用户组(可以不创建,使用默认和用户名相同的组)
groupadd groupname
2. 创建用户并指定用户组
useradd -g groupname username
或者使用默认用户组,配置网站服务的用户不建议如此做
useradd username
3. 修改用户密码
passwd username
4.赋予用户一定的root的权限(如果没有特殊需要一般网站服务不需要)
visudo
在最后一行添加:
username ALL=(root) /usr/bin/*, /usr/local/elasticsearch-2.4.4/*, !/usr/bin/passwd [A-Za-z]*
注意:ALL=(root)是说su只能切换到root用户, 后面用逗号隔开的是用户的权限,/usr/bin/*表示可以执行基本命令,/usr/local/elasticsearch-2.4.4/*是我自己的elasticsearch的文件路径下所有权限, !/usr/bin/passwd [A-Za-z]*表示不可以修改除了自己的所有用户的密码。
5.将网站的项目根目录的所属者分配给新增的用户
我们假设http服务器运行的用户和用户组是www,网站用户为centos,网站根目录是/home/centos/web。
方法/步骤:
1
我们首先设定网站目录和文件的所有者和所有组为centos,www,如下命令:
chown -R centos:www /home/centos/web
2
设置网站目录权限为750,750是centos用户对目录拥有读写执行的权限,这样centos用户可以在任何目录下创建文件,用户组有有读执行权限,这样才能进入目录,其它用户没有任何权限。
find -type d -exec chmod 750 {} \;
3
设置网站文件权限为640,640指只有centos用户对网站文件有更改的权限,http服务器只有读取文件的权限,无法更改文件,其它用户无任何权限。
find -not -type d -exec chmod 640 {} \;
4
针对个别目录设置可写权限。比如网站的一些缓存目录就需要给http服务有写入权限。例如discuz x2的/data/目录就必须要写入权限。
find data -type d -exec chmod 770 {} \;
经过以上设置之后,就可以使用指定的用户去启动网站的服务了,而不是再如同上面测试环境中使用root启动这个服务,使用root启动服务是不安全的。
uWSGI开机启动服务
继续以django的项目为例,让uWSGI开机就启动服务,编辑文件/etc/rc.local
, 添加下面内容到这行代码之前exit 0
:
/..uwsgi再系统中的路径../uwsgi --ini /..Django项目中uwsgi配置文件的路径../uwsgi_luffy.ini
要注意的是记得ini配置文件中设置好用户用户组,sock
文件,sock文件的权限
和后台运行
等配置。
二、Nginx部署
- Nginx的作用主要是监听作用,当客户端有静态请求时,将请求指定的静态文件返回给客户端;当客户端发送的是动态url请求时,将该请求从监听端口取出交给uwsgi服务的监听端口,uwsgi的端口接到请求后,交给项目文件夹下的各个Django服务(视图中的函数)进行处理,处理好之后,再由uwsgi返回给nginx,最后nginx将内容返回给客户端。
- 可以理解到,这就是一个三者合作的过程。因此,我们这一步的配置主要是需要配置nginx的监听端口,以及接收到动态请求后,需要交给哪一个uwsgi的监听端口去处理。除此之外,还要配置nginx本身的静态需求文件夹,包括了项目的根目录、项目的静态文件夹static路径,以及媒体文件夹media路径。
下面是我的项目配置情况:
nginx配置uwsgi和django
-
将
uwsgi_params
文件拷贝到项目文件夹下。
uwsgi_params
文件一般在/etc/nginx/
目录下,也可以从nginx
的github
页面下载。 -
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;
- 拷贝到项目下:
sudo cp /etc/nginx/uwsgi_params /..项目目录../
- 属主属组等权限重新修改
sudo chown www:centos uwsgi_params
sudo chmod 664 /..项目所在的目录../uwsgi_params
- 在项目文件夹下创建文件nginx.conf,填入并修改下面内容:
http{
include /etc/nginx/mime.types;
upstream django {
# server unix:///path/to/your/mysite/mysite.sock;
# 用于文件套接字
server 127.0.0.1:8000;
# 用于Web端口套接字(我们将首先使用它)
}
# //解决web部署到nginx后js,css等不能访问。
# 服务器配置
server {
#您的网站将在其上服务的端口
listen 80; #nginx的监听端口,相当于是我们提供服务的第一道墙
# 指定提供服务的主机地址,我们将uwsgi服务于nginx服务配置再一台服务器的,因此指定本机即可
server_name 127.0.0.1;
# 设置nginx传送内容的字符集格式,解决网页乱码问题
charset utf-8;
# 设置请求体大小;可用于解决大文件上传不了的问题
client_max_body_size 500M; # adjust to taste
location / {
uwsgi_pass django;
include /web/GradingSystem/uwsgi_params;
# 您安装的uwsgi_params文件(这个很重要,我是将uwsgi的这个文件拷贝到了项目文件夹下面)
}
location /static/ {
alias /web/GradingSystem/static/;
# 您的Django项目的静态文件-根据需要进行修改
}
# Django media
location /media/ {
alias /web/GradingSystem/static/media/;
# 您的Django项目的媒体文件-根据需要进行修改
}
# 最后,将所有非静态和媒体请求发送到Django服务器。
}
}
events {
worker_connections 1024; ## Default: 1024
}
- 补充一些相关参数的意思:
1.client_max_body_size
- 限制请求体的大小,若超过所设定的大小,返回413错误。
2.client_header_timeout
- 读取请求头的超时时间,若超过所设定的大小,返回408错误。
3.client_body_timeout
- 读取请求实体的超时时间,若超过所设定的大小,返回413错误。
4.proxy_connect_timeout
- http请求无法立即被容器(tomcat, netty等)处理,被放在nginx的待处理池中等待被处理。此参数为等待的最长时间,默认为60秒,官方推荐最长不要超过75秒。
5.proxy_read_timeout
- http请求被容器(tomcat, netty等)处理后,nginx会等待处理结果,也就是容器返回的response。此参数即为服务器响应时间,默认60秒。
6.proxy_send_timeout
- http请求被服务器处理完后,把数据传返回给Nginx的用时,默认60秒。
这个配置文件告诉nginx从文件系统中拉起media和static文件作为服务,
同时响应django的request。
为此,我也在相应的项目目录下先建立起media和static文件夹。
为方便nginx运行时使用配置信息,创建一个nginx.conf的软链接到nginx默认的sites-enabled
目录。
sudo ln -s /..项目所在../nginx.conf /etc/nginx/sites-enabled/nginx.conf
如果不生成这个软连接,那么Nginx启动时默认加载的配置文件就是它默认的那一个,当然可以使用nginx -c /.../nginx.conf
命令启动nginx,它将加载指定配置文件的配置信息,并启动nginx。
django部署static文件(如果项目已经有了static,可以确认一下目录路径是否正确)
- 在项目文件夹下,建立好静态文件目录:
mkdir static
- django的setting文件中,添加一行:
STATIC_ROOT = os.path.join(BASE_DIR, “static/”)
- 运行(
这个必须得运行
)
python manage.py collectstatic
- 在项目文件夹下,建立一个media媒体文件目录(用于存放图片音乐等文件做测试)
mkdir media
-
在media目录中,我传入了一个图片文件2333.png用于测试nginx。
-
参数STATIC_ROOT用在哪?
通过python3 manage.py collectstatic
收集所有你使用的静态文件保存到STATIC_ROOT! -
STATIC_ROOT 文件夹 是用来将所有STATICFILES_DIRS中所有文件夹中的文件,以及各app中static中的文件都复制过来,把这些文件放到一起是为了用nginx等部署的时候更方便。
重新加载nginx配置文件进行测试
- 先进行检测,看之前的配置文件有无错误。
sudo /usr/sbin/nginx -t
- 重新加载nginx让软链接的luffy_nginx.conf生效。
sudo /usr/sbin/nginx -s reload
- 访问
http://..ip_advers..:80/media/2333.png
看能否正常访问到图片资源,注意这里我们使用的服务端口是为nginx服务运行的端口。
注意在做这一步之前,我是己经配置好域名和传送了一个用于测试的图片到服务器上。
做这一步的时候,我也遇到了很多坑,报了很多莫名奇妙的错,但是总结一下,如果nginx服务有问题,请使用systemctl status nginx
查看服务状态,使用systemctl restart nginx
命令重启nginx服务,再进行测试。
我己经能成功访问到资源了,所以接下来再做下一步测试。
测试nginx 应用 uWSGI 和 test.py
还记得之前写好的一个测试的test-uwsgi.py文件吗?
我们就用配置好的nginx来访问uwsgi启动的test-uwsgi.py好了。
首先,启动uwsgi,并且端口是nginx配置中的负载均衡池8000端口:
uwsgi --socket :8000 --wsgi-file test-uwsgi.py
访问http://ip:80/
,实际上访问的就是uwsgi的8000端口。
如能正常访问。表明下面的环节通畅:
the web client <-> the web server <-> the socket <-> uWSGI <-> Python
测试成功后中止程序,到此为止,我们将服务器的uwsgi与nginx和Django三者的关系打通了,最后以 Nginx,WSGI,Django 之间的对话再来阐述一下三者的关系:
Nginx:Hey,WSGI,我刚收到了一个请求(动态http请求),我需要你作些准备,然后由Flask来处理这个请求。
WSGI:OK,Nginx。我会设置好环境变量,然后将这个请求传递给Django处理。 Django:Thanks
WSGI!给我一些时间,我将会把请求的响应返回给你。 WSGI:Alright,那我等你。
Django:Okay,我完成了,这里是请求的响应结果,请求把结果传递给Nginx。 WSGI:Good
job!Nginx,这里是响应结果,已经按照要求给你传递回来了。 Nginx:Cool,我收到了,我把响应结果返回给客户端。大家合作愉快~
欢迎评论区留言,哪里写的不对的烦请提出,我及时修改,大家共同进步!