这篇文章主要围绕Nginx+uWSGI+Python+Django构建必应高清壁纸站展开,旨在为您提供一份详细的参考资料。我们将全面介绍Nginx+uWSGI+Python+Django构建必应高清壁
这篇文章主要围绕Nginx + uWSGI + Python + Django构建必应高清壁纸站展开,旨在为您提供一份详细的参考资料。我们将全面介绍Nginx + uWSGI + Python + Django构建必应高清壁纸站,同时也会为您带来12.13 Nginx 防盗链 12.14 Nginx 访问控制 12.15 Nginx 解析 php 相关配置 12.16 Nginx 代理、6 月 11 日任务 Nginx 防盗链、Nginx 访问控制、Nginx 解析 php 相关配置、Nginx 代理、debian10+Nginx+Flask+uWSGI+uWSGI Emperor配置流程、Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项的实用方法。
本文目录一览:- Nginx + uWSGI + Python + Django构建必应高清壁纸站
- 12.13 Nginx 防盗链 12.14 Nginx 访问控制 12.15 Nginx 解析 php 相关配置 12.16 Nginx 代理
- 6 月 11 日任务 Nginx 防盗链、Nginx 访问控制、Nginx 解析 php 相关配置、Nginx 代理
- debian10+Nginx+Flask+uWSGI+uWSGI Emperor配置流程
- Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项
Nginx + uWSGI + Python + Django构建必应高清壁纸站
写在前面
做这个网站的初衷是因为,每次打开必应搜索搜东西的时候都会被上面的背景图片吸引,我想必应的壁纸应该是经过专业人员精选出来的,我甚至会翻看以前的历史图片,唯一美中不足的是必应的首页只能查看最多7天的壁纸。所以我萌生出自己建一个网站,每天定时搜集必应的壁纸,将壁纸信息保存在数据库中,这样就可以看到很久之前的壁纸图片了。网站使用的是python的django框架,前端接入使用了nginx+uwsgi。没什么特别的考虑,其实网站本身没什么技术含量,使用python的django入手还是很快的,当然用nodejs+express也是不错的(其实我的node比python熟,想折腾点新东西哈哈)。我在这里写出步骤来,给刚刚上手的朋友们一个参考。服务器是直接购买的阿里云的,第一年很便宜才100不到好像,1核2G的基础配置带宽也低,不过够用了。域名直接在万网购买,其实也是阿里旗下,备案也很方便,按照提示步骤操作,差不多2周以内就下来了。最终的成果可以到这里先睹为快:必应高清壁纸,必应每日一图
安装python环境
我们使用的是最新的django框架,需要比较新版本的python环境,阿里云的服务器我购买的时候选择的是centos 6.9,不过我觉得操作系统版本对后面的操作影响不大,服务器内置都已经安装有python环境,只不过是python2.6.6比较老的版本了。所以为了使用最新的django 3.0.1,我干脆安装最新的python 3.8.1。这里我自己下载python源码进行编译,安装。
wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tgz
tar zxvf Python-3.8.1.tgz
cd Python-3.8.1
./configure
make
make install
安装好之后,python2.6与python3.8是共存的,我们可以使用python3命令来使用3.8.1版本的python,通过下面的命令可以看到我们安装的python3.8被安装到的目录:
$ which python3
/usr/local/bin/python3
$ ll /usr/local/bin/python3
/usr/local/bin/python3 -> python3.8
跟随python3一起安装的还有pip3,是python的包管理工具,python2.x用的是pip,python3.x用的是pip3。接下来我们安装django框架
安装django框架
pip3 install django
结果报告下面的错误:
看提示是ssl的版本过低,而python需要更高的版本,使用命令 openssl version 查看得到当前系统安装的openssl的版本是1.0.1e,而python3.8需要openssl版本为1.0.2或者以上的版本。这里我们安装openssl 1.1.1的版本:
# 下载源码编译安装
wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar -zxvf openssl-1.1.1a.tar.gz
cd openssl-1.1.1a
./config --prefix=/usr/local/openssl no-zlib
make
make install
# 替换系统目录中低版本的库
mv /usr/bin/openssl /usr/bin/openssl.bak
mv /usr/include/openssl/ /usr/include/openssl.bak
ln -s /usr/local/openssl/include/openssl /usr/include/openssl
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/local/lib64/libssl.so
ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so
# 加入库搜索路径并使之生效
echo "/usr/local/openssl/lib" >> /etc/ld.so.conf
ldconfig -v
# 查看openssl版本输出:OpenSSL 1.1.1a 20 Nov 2018
openssl version
这样新版openssl就安装好了,我们再重新编译并安装Python3,如下:
cd Python-3.8.1
./configure --with-openssl=/usr/local/openssl
make
make install
这里的3.8.1编译的时候是添加 --with-openssl=/usr/local/openssl 这个选项,而不是网上的资料说的 --with-ssl 网上说的这个选项是错的,会报错 unrecognized options 。除此以外还有一个问题让我费了点时间值得注意一下,就是在openssl进行make install之后,重新编译python3.8的时候,编译结束总是有下面的错误提示:
Could not build the ssl module!
Python requires an OpenSSL 1.0.2 or 1.1 compatible libssl with X509_VERIFY_PARAM_set1_host().
就是提示找不到ssl,该错误提示还是因为编译python的时候 -ssl 选项没有找到正确的 libssl.so 的动态库。我们可以通过下面的命令来确定当前系统中的ssl动态库的情况:
ldconfig -v | grep ssl
# 在其输出中我们要确定是否还有老的ssl库在里面,实际上在编译提示找不到ssl的时候
# 我通过命令查看的结果发现 /usr/lib64/libssl.so 软链的还是 1.0.1 的老版本
# 于是我改成连接到新编译的 1.1.1 版本之后,最后看到的是下面的结果
libssl.so.1.1 -> libssl.so.1.1
libssl3.so -> libssl3.so
libssl.so.10 -> libssl.so.1.0.1e
之后再重新编译python就没有报ssl not found的错误了,说明新版ssl已经编译到python3.8.1中,此时我们再用上面的命令安装django,最后得到下面的提示,表示安装成功完成:
Installing collected packages: sqlparse, pytz, asgiref, Django
Successfully installed Django-3.0.5 asgiref-3.2.7 pytz-2019.3 sqlparse-0.3.1
这里要注意的是,网络很慢的情况下会经常超时,我之后是通过wget手工下载之后再进行安装的:
wget https://files.pythonhosted.org/packages/a9/4f/8a247eee2958529a6a805d38fbacd9764fd566462fa0016aa2a2947ab2a6/Django-3.0.5-py3-none-any.whl
pip3 install ./Django-3.0.5-py3-none-any.whl
安装成功之后,我们通过下面的方法验证是否正常:
python3
Python 3.8.1 (default, Apr 18 2020, 00:10:11)
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> print(django.get_version())
3.0.5
就是直接运行python3,打开python3的交互输入,引用django模块,打印出其版本,正确打印出了我们安装的3.0.5版本,说明安装正常了
配置django
django框架安装正常之后,我们建立一个简单的django工程testdj如下:
django-admin.py startproject testdj
创建完成之后,会在当前目录下创建一个目录与工程名同名 testdj,我们看下该目录的结构:
这样我们的django项目就创建好了,我们通过其提供的管理脚本 manage.py 来启动他:
# 注意这里要用python3来运行
python3 manage.py runserver 0.0.0.0:8000
运行之后报错了:
由于django3.0.5版本默认引用了sqlite3的数据库,我们并没有安装sqlite3,所以报错,我们先在 settings.py 中把这个配置去掉:
再次运行之后正常,但是此时我们还不能在浏览器中访问他,我们需要编写对应的页面,因为此时项目中什么都没有,连主页都没有,运行成功如下图:
编写视图以及设置url路由
下面我们为主页的请求编写一个view并配置一下路由规则,让主页请求路由到我们编写的view上,在上面的目录结构里面,与 settings.py 同一目录下添加文件 view.py 内容如下:
# view.py
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world ! ")
修改urls.py的内容如下:
# urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from . import view
urlpatterns = [
url(r''^$'', view.hello),
]
将 settings.py 中的 ALLOWED_HOSTS 配置修改为如下:
# 如果不修改会报类似的错误
# Invalid HTTP_HOST header: ''ip:8000''. You may need to add ''ip'' to ALLOWED_HOSTS.
ALLOWED_HOSTS = [''*'']
再次启动项目之后,在浏览器通过地址访问得到正确输出:
此时我们的diango顺利启动,下面我们在django中使用数据库,django中默认配置sqlite3,我们这里为演示方便,也使用sqlite3作为例子,相信换成其他的数据库不难
在django中使用sqlite3
我们使用sqlite3这个小巧简单的单文件数据库来做演示,sqlite3虽然结构简单,但是功能可一点不简单,支持大多数常见的sql语法,首先我们需要安装sqlite3:
wget https://www.sqlite.org/2018/sqlite-autoconf-3240000.tar.gz
tar -xvzf sqlite-autoconf-3240000.tar.gz
cd sqlite-autoconf-3240000/
./configure --prefix=/usr/local/sqlite
make
make install
编译完成之后,我们需要重新编译与安装python3.8.1,按照上面编译python3的流程重新跑一遍(包括 ./configure --with-openssl=/usr/local/openssl
) ,重新编译python3之后,我们可以打开python3的输入交互环境,直接在里面 import sqlite3 没有报错,即sqlite3可以在python3中正常使用了,如果有报错的话,按照我们上面解决 openssl 的思路去定位类似的问题,相信应该很好解决。在调用configure配置python3的时候,会生成 config.log 里面也可以查看到一些出错信息。接下来我们首先生成一个sqlite3的数据库文件,并创建一个表,插入测试数据,过程如下:
# 我们的数据库文件的名字取 db.sqlite3
sqlite3 db.sqlite3
create table "tb_message"
(
"message_id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"message_user" varchar(255) NOT NULL,
"message_content" text default ''''
);
insert into tb_message(message_user,message_content)values(''张三'',''这是张三发送的消息'');
insert into tb_message(message_user,message_content)values(''李四'',''这是李四发送的消息'');
将生成的数据库文件的名字放在想要放置的目录下,为了测试方便,我们将其放在django工程的根目录,我们将在django项目中读出表的数据并展示到网页上,为了使用django的model,我们需要先创建一个app,在django工程的根目录下使用下面的命令创建一个名字为djapp的app:
django-admin startapp djapp
我们看到创建了一个djapp的文件夹,我们看看djapp的目录结构:
我们前面为了顺利运行django项目,将settings.py中关于sqlite的配置注释了,现在我们需要将这些配置正常化,同时我们刚才创建的djapp我们要在 settings.py 配置中添加进来:
# settings.py
# 这里配置了数据库文件所在的路径
DATABASES = {
''default'': {
''ENGINE'': ''django.db.backends.sqlite3'',
''NAME'': os.path.join(BASE_DIR, ''db.sqlite3''),
}
}
...
# Application definition
INSTALLED_APPS = [
''django.contrib.admin'',
''django.contrib.auth'',
''django.contrib.contenttypes'',
''django.contrib.sessions'',
''django.contrib.messages'',
''django.contrib.staticfiles'',
''djapp'',
]
生成model定义,也就是 djapp/models.py 的内容,在django中,我们可以自己编写models.py的内容,然后使用相关的命令生成数据库的表结构,反过来我们可以自己定义好表结构,使用相关命令由表结构去生成model的类定义。我一般习惯于自己定义好数据库的表结构,然后使用命令生成model的类定义,下面我们生成model类定义到文件 djapp/models.py 中:
# 我们在manage.py所在的目录运行下面的命令
python3 manage.py inspectdb > djapp/models.py
我们可以在 djapp/models.py 文件中看到生成的model定义的内容,一个数据库表对应一个class,我们只创建了一个表,所以文件中只有一个模型类,要注意的是这一步骤的前提是必须在 settings.py 中设置sqlite3的相关配置:
from django.db import models
class TbMessage(models.Model):
message_id = models.AutoField(primary_key=True)
message_user = models.CharField(max_length=255)
message_content = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = ''tb_message''
接着我们修改之前 view.hello 的实现,在里面读取数据库表的记录,并将数据呈现到模板文件中,再编写模板文件之前,我们需要在 settings.py 中设置模板文件所在的目录:
TEMPLATES = [
{
''BACKEND'': ''django.template.backends.django.DjangoTemplates'',
''DIRS'': [BASE_DIR+"/templates"],
''APP_DIRS'': True,
''OPTIONS'': {
''context_processors'': [
''django.template.context_processors.debug'',
''django.template.context_processors.request'',
''django.contrib.auth.context_processors.auth'',
''django.contrib.messages.context_processors.messages'',
],
},
},
]
我们将模板文件放在项目根目录下的 templates 目录下,我们在此目录下新建一个模板文件 test.tmp 内容如下:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>django test</title>
</head>
<body>
{% for msg in msg_list %}
<div>用户名:{{ msg.message_user }} 消息:{{ msg.message_content }} </div>
{% endfor %}
</body>
</html>
django的模板提供各种包括if、for、过滤器等丰富的模板标签来控制模板的呈现逻辑,使用过MVC方式编写Web应用程序的应该很容易理解,具体的用法很容易在网络上找到,我也不再说明了,上面的模板实际上就是将后端返回的数据中对应的model数据呈现到模板文件中,然后返回最终呈现的HTML内容,我们的 testdj/view.py 的内容如下:
# view .py
from django.http import HttpResponse
from django.shortcuts import render
from django.http import JsonResponse
from djapp.models import TbMessage
def hello(request):
xlist = TbMessage.objects.all().order_by(''message_id'')
msg_list = []
context={"msg_list":msg_list}
for msg in xlist:
msg_list.append({"message_user":msg.message_user,"message_content":msg.message_content})
return render(request, ''test.tmp'', context)
django生成的模板类提供了丰富的访问数据库的能力,包括按各种条件去查询数据库以及进行排序等,另外通过 Model.objects.raw() 函数可以直接写自定义的sql,数据访问这部分更多的函数功能可以查询django的文档,这里也不在浪费篇幅说明了,上述操作好之后,我们再启动django的项目,输入网址,在网页上就能看到结果了:
至此我们的django项目已经运行起来了,并且可以访问sqlite3数据库中的数据,我们列出目前为止整个项目目录的结构以及其说明,方便大家参考:
到目前为止我们运行django项目都是通过项目目录下的 manage.py 进行运行,此种方式仅仅是django为方便调试而提供的一个简易的web服务器,在线上环境我们肯定不能这么使用,那么接下来我们需要通过 Nginx、uWSGI与django结合的方式搭建可以在线上部署的方案
安装uWSGI
在开始这个话题之前,我们首先来说明几个比较重要的概念:
首先要说明的是WSGI,他的全称叫做Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。WSGI 不是框架,也不是一个模块而是一个接口规范,是Web服务器与Web应用之间的一种通信规范,该规范不仅仅局限于Python语言,任何语言编写的Web服务器和Web应用程序之间都可以使用WSGI来通信。WSGI标准在 PEP 333 中定义并被许多框架实现,其中包括现我们这里的django框架
说了这么多到底WSGI是什么呢,WSGI只是一种规范,是用于Web服务器和Web应用程序之间通信用的,Web服务器我们知道是提供HTTP服务的服务端程序,例如Nginx、Apache Http Server、Windows IIS 都是常见的Web服务器程序,那么Web应用程序又是什么呢。讲这个之前我们需要先回顾一下Web程序的发展历史,HTTP协议出来之后,作为服务端的实现,Web服务器开始只能提供对静态资源的访问,例如html、图片资源等等,像下面的形式:
人们不满足于只获取静态的网页内容,就出现了动态的网页技术,由Web服务器调用一个外部的程序来生成动态的HTML内容返回给浏览器端。而这个外部的程序可以使用shell,也可以使用perl等脚本编写,或者干脆使用C语言编写,这些程序可以访问外部数据源来生成HTML。那么Web服务器程序与这个生成动态HTML内容的外部程序之间通过什么来传递请求参数呢,Web服务器又通过什么方式来获得并返回由外部程序生成的动态HTML内容呢。由此定义了一个规范,也即是Common Gateway Interface,公共网关接口规范,就是我们常说的CGI了,这些被Web服务器调用的外部程序也因此被称为CGI程序。CGI规范规定:CGI程序从他的标准输入中,接受Web服务器的输入(例如请求参数),并通过标准输出将生成的HTML内容返回给Web服务器。HTTP请求中的一些变量(例如Host,客户端ip地址,浏览器的Agent信息等)则是由Web服务器设置在环境变量中,再由CGI程序从环境变量中读取,这种请求模式变成下面的图:
之后出现了CGI规范的改进版,也即FastCGI规范,FastCGI程序与Web服务器之间的通信并不是通过标准输入与输出,也不通过环境变量来与Web服务器交换HTTP的变量信息,FastCGI程序本身是一个独立的服务端程序,其通过socket监听端口,与Web服务器通信,只不过通信协议使用FastCGI协议而已。那么我们这里说的CGI程序与FastCGI程序是用来处理动态的Web请求并动态生成HTML内容返回给Web服务器的,他们就是我们所说的Web应用程序。随着动态语言的发展,涌现出了越来越多的动态网页技术,但是总归其模式与上面讲的差异不大,例如我们常见的语言的请求结构如下图所示:
之所以需要Web服务器与Web应用程序这种架构,是因为Web服务器本身不处理动态内容,动态内容的处理交给Web应用程序去处理,Web应用程序由广大的程序员根据自己的业务需求使用各种各样的语言去编写,而Web服务器与Web应用程序之间通过某种规范或者说协议来规定怎样去通信,这就出现了各种语言框架下实现的CGI、FastCGI、Servlet、Rack、WSGI等协议或规范,Web服务器与Web应用程序之间如果都遵循相同的协议或实现相同的规范,理论上应该是与语言无关的,由于各种各样的原因,有些规范或者协议,只在特定的语言的web框架中出现或者说多数情况下是这样,例如Servlet在Java中使用,Rack在Ruby中使用
在一些情况下Web服务器与Web应用程序是两个独立的进程,他们通过socket进行通信,通信协议是双方都支持的协议规范(例如FastCGI)。还有一些情况Web服务器与Web应用程序之间的通信是紧耦合的,比如IIS是通过ISAPI的方式,实际上是加载一个dll,调用dll中的相关功能与.NET Web应用交互的。当Nginx与Python Django结合的时候他支持这两种方式,一种是 Nginx+mod_wsgi 方式,这种方式下由Nginx去调用 mod_wsgi 模块中的功能,进而调用python的Web应用程序功能动态生成HTML,其运行的上下文环境在 Nginx 进程中:
另一种方式就是上面截图中展示的通过socket与uWSGI进程交互的方式,Web服务器与uWSGI通信的协议可以是 HTTP 协议,也可以是二进制的 uwsgi 协议,uWSGI程序支持这两种方式与之通信,我们这里使用二进制 uwsgi 协议的方式,不过我们首先要安装 uWSGI 程序(终于说到本章的正题了,前面讲原理都是做铺垫):
pip3 install uwsgi
ModuleNotFoundError: No module named ''_ctypes''
报错找不到模块 ''_ctypes'' 经查询我们需要安装 libffi-devel 命令如下:
yum install libffi-devel -y
安装完成之后,我们需要重新配置Python3.8.1并重新make以及make install,命令在上面都有,这里就不重复说了,完成之后继续安装 uwsgi 没有报错,安装成功,我们尝试用下面的命令通过uwsgi启动django应用:
uwsgi --http :8000 --wsgi-file testdj/wsgi.py
我们之前说过uWSGI程序支持两种方式接受请求,一种是使用 HTTP 协议,另一种是使用二进制的 uwsgi 协议,这里我们需要在浏览器中直接访问,所以我们这里运行 uwsgi 的时候通过 --http 选项指定 http 协议,并指定 wsgi 应用文件所在的路径为django项目根目录下的 testdj/wsgi.py 文件,启动之后在浏览器中输入地址直接访问即可正确出结果,截图与前面一样。接下来我们需要使用 Nginx 来作为Web服务器并通过uwsgi进程与wsgi应用来处理动态请求。为什么我们需要Nginx呢,上面运行uwsgi不是已经可以直接使用了吗,我们在之前已经说过了,现在的网站的结构一般都是 Web服务器程序 + 动态语言程序 的结构,是因为各个模块应该各自做自己擅长的事,wsgi应用擅长处理动态的http请求并生成动态的HTML内容,Nginx是专业的Web服务器擅长其他的HTTP请求的处理,事实上uWSGI程序中实现了一个简陋的HTTP服务,所以我们才可以通过 HTTP 的方式直接在浏览器中访问他,然而如果静态资源也用他来处理,其性能肯定比Nginx差很多,所以这里要引入Nginx,引入Nginx的另一个好处是还可以做负载均衡
安装Nginx
首先我们需要安装Nginx服务,Nginx是使用非常广泛的高性能Web服务器,在CentOS下安装也非常简单:
yum install nginx
没有任何报错,直接安装完成,当然自己下载源码安装想要的版本也很方便,下面我们需要配置Nginx,安装之后的nginx的配置文件地址在 /etc/nginx/conf.d/default.conf
server {
...
listen 80;
# 静态文件请求
location /static {
alias /data/testdj/static/;
}
# uwsgi_pass 转向到uWSGI的8000端口
location / {
uwsgi_pass 127.0.0.1:8000;
include /etc/nginx/uwsgi_params;
}
...
}
这里我列出了比较关键的配置,第一个static匹配用于请求静态资源,我们的静态资源可以放在一个单独的 static 目录中,这样静态资源请求不会转发到 uWSGI 去处理,而是直接由 Nginx 处理返回,其他的请求我们通过 uwsgi_pass 配置转发到本机的 8000 端口上,实际上这个配置表明我们的 uWSGI 进程开启的是以 uwsgi 二进制协议进行 socket 通信的8000端口,而不是上面的 HTTP 协议的 8000 端口,如果是 HTTP 协议的8000端口,这里直接配置一个普通的 http 代理即可,配置完成之后 ,我们以下面的命令启动 uWSGI程序:
uwsgi --socket 127.0.0.1:8000 --wsgi-file testdj/wsgi.py
我们这里使用的是 --socket 而不是 --http 并且监听的是 127.0.0.1 这个地址,因为我们的Nginx与uWSGI进程运行在同一台机器上,这个端口就不用暴露到外面了,启动 uWSGI 之后,我们启动 Nginx进程,直接在浏览器中输入 http://ip 即可以正常访问了
在后端运行uWSGI进程
我们前面通过 uwsgi 命令启动uWSGI的方式,程序跑在我们shell环境的前端,如果我们的终端连接断掉则程序会退出,我们需要以后端服务的形式运行uWSGI,这里我们需要将 uWSGI 运行所需要的参数放到一个配置文件中,我们将这些参数放在 uwsgi.ini 中,当然这个文件名字以及放置的具体路径并没有特殊要求,文件内容如下:
# uwsgi.ini
[uwsgi]
# uWSGI的端口
socket = 127.0.0.1:8000
# 直接作为web服务器使用
# http=ip:port
# django项目目录
chdir = /data/testdj
# 以django项目名命名的wsgi文件,实际上这个文件是不存在的
# 但是配置必须这么配
module = testdj.wsgi
master = true
#进程数
processes = 4
threads = 2
vacuum = true
# 保存启动之后主进程的pid
pidfile=uwsgi.pid
# 设置uwsgi后台运行,uwsgi.log保存日志信息
daemonize=uwsgi.log
设置好之后,我们在 uwsgi.ini 文件所在的目录运行下面的命令即可(Nginx不用重启):
# -d 参数表示从后台运行
uwsgi -d --ini uwsgi.ini
再次访问网页,大功告成
收集必应壁纸
文章开头我们说我们要建立一个必应壁纸的收集展示网站,其实主要是介绍 Nginx+uWSGI+Django 的使用,因为网站使用的是 Python语言和Django框架,所以搭建网站也费了一些周折,这个是耗时最多的,其实环境搭建好之后,代码的编写反而很简单,在django中编写程序很方便。收集必应壁纸本身并没有什么特别要说明的,就是下载每天的必应美图,将图片保存到自己的网站,并将相关信息入库,在网站上展示出来。不过呢这里简单说一下怎么获取必应的背景壁纸,有一种很容易想到的方法是直接在代码里面请求必应的网站,然后查看网页结构,获取必应壁纸的url,不过必应的壁纸并没有这么麻烦,通过在Chrome浏览器中访问必应网站发现,必应其实有提供接口,如下:
通过在Chrome浏览器中请求必应网站,选择 "XHR" 可以看到必应的壁纸是通过一个 Ajax 请求获取的数据,我们找到这个请求即可,我贴出来:
https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1587287726147&pid=hp
这个接口里面的参数是可以设置的,format表示返回的数据的格式 js 返回的是json格式的数据,n 应该是返回的图片的张数,idx 应该是分页的参数,具体的参数含义,大家可以去网上搜索一下,已经有一些人研究过了。不过好像无论怎么设置,并没有办法获取太久的历史图片数据,必应的官网上也只能看到最近一周的图片。也因如此,才有了本篇文章,必应壁纸收集站的实现完全使用上面提到的技术,网站也会持续完善中,欢迎大家来这里反馈留言:关于必应高清壁纸。另外服务器我直接从阿里云买的低配版本机器,带宽和性能都比较基础,目前来说是够用的,域名是直接从万网购买并备案的,其实整个流程还是很便捷的,而且第一年的价格很便宜。 到此本篇介绍就完结了,希望对大家使用django搭建web网站有所帮助
12.13 Nginx 防盗链 12.14 Nginx 访问控制 12.15 Nginx 解析 php 相关配置 12.16 Nginx 代理
12.13 Nginx 防盗链
因为该配置也使用 location 板块,所以本节可结合日志管理(不记录和过期时间)一起配置:
[root@cham002 ~]# vim /usr/local/nginx/conf/vhost/test.com.conf
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.test.com ;
#定义referer白名单
if ($invalid_referer) {
return 403;
#if函数的意思是:如果不是白名单内的域名,返回值:403
}
access_log off;
}
说明: “location ~* ^.+” 在此 0“ * ” 的作用是后面匹配的内容不区分大小写。
检测及测试
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -s reload
[root@cham002 ~]# ls /data/wwwroot/test.com/
1.gif 2.js admin index.html
[root@cham002 ~]# curl -e "http://www.baidu.com/1.txt" -x127.0.0.1:80 -I test.com/1.gif
HTTP/1.1 403 Forbidden
Server: nginx/1.12.1
Date: Wed, 03 Jan 2018 13:54:39 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
[root@cham002 ~]# curl -e "http://www.test.com/1.txt" -x127.0.0.1:80 -I test.com/1.gif
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Wed, 03 Jan 2018 13:55:14 GMT
Content-Type: image/gif
Content-Length: 32
Last-Modified: Wed, 03 Jan 2018 13:34:18 GMT
Connection: keep-alive
ETag: "5a4cdbda-20"
Expires: Wed, 10 Jan 2018 13:55:14 GMT
Cache-Control: max-age=604800
Accept-Ranges: bytes
即,使用非白名单内的 referer 进行访问,被拒绝!!!
12.14 Nginx 访问控制
需求:访问 /admin/ 目录的请求,只允许几个指定 IP 通过,配置如下:
[root@cham002 ~]# vim /usr/local/nginx/conf/vhost/test.com.conf
server
{
listen 80;
server_name test.com test2.com test3.com;
index index.html index.htm index.php;
root /data/wwwroot/test.com;
if ($host != ''test.com'' ) {
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
# location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
# {
# expires 7d;
# access_log off;
# }
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.test.com ;
if ($invalid_referer) {
return 403;
}
access_log off;
}
location ~ .*\.(js|css)$
{
expires 12h;
access_log off;
}
location /admin/
{
allow 127.0.0.1;
allow 192.168.230.135;
deny all;
#设置IP白名单
}
access_log /tmp/test.com.log cham;
}
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -s reload
测试 (针对目录的)
[root@cham002 ~]# curl -e "http://www.baidu.com/1.txt" -x127.0.0.1:80 -I test.com/admin/
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 07:59:16 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Wed, 03 Jan 2018 08:50:53 GMT
Connection: keep-alive
ETag: "5a4c996d-14"
Accept-Ranges: bytes
[root@cham002 ~]# curl -x192.168.230.150:80 -I test.com/admin/
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 08:01:00 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Wed, 03 Jan 2018 08:50:53 GMT
Connection: keep-alive
ETag: "5a4c996d-14"
Accept-Ranges: bytes
[root@cham002 ~]# curl -x192.168.230.135:80 -I test.com/admin/
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 08:01:14 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Wed, 03 Jan 2018 08:50:53 GMT
Connection: keep-alive
ETag: "5a4c996d-14"
Accept-Ranges: bytes
[root@cham002 ~]# cat /tmp/test.com.log
127.0.0.1 - [03/Jan/2018:21:35:36 +0800] test.com "/index.html" 200 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:15:59:16 +0800] test.com "/admin/" 200 "http://www.baidu.com/1.txt" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:00 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:14 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
[root@cham002 ~]# curl -x192.168.230.150:80 -I test.com/admin/
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 08:01:37 GMT
Content-Type: text/html
Content-Length: 20
Last-Modified: Wed, 03 Jan 2018 08:50:53 GMT
Connection: keep-alive
ETag: "5a4c996d-14"
Accept-Ranges: bytes
[root@cham002 ~]# cat /tmp/test.com.log
127.0.0.1 - [03/Jan/2018:21:35:36 +0800] test.com "/index.html" 200 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:15:59:16 +0800] test.com "/admin/" 200 "http://www.baidu.com/1.txt" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:00 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:14 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:37 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
[root@cham002 ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.230.135 netmask 255.255.255.0 broadcast 192.168.230.255
inet6 fe80::6f15:52d3:ebeb:e193 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:b6:9f:e3 txqueuelen 1000 (Ethernet)
RX packets 96831 bytes 41894507 (39.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 60974 bytes 20136998 (19.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.230.150 netmask 255.255.255.0 broadcast 192.168.230.255
ether 00:0c:29:b6:9f:e3 txqueuelen 1000 (Ethernet)
ens37: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.100.1 netmask 255.255.255.0 broadcast 192.168.100.255
inet6 fe80::1801:cbbb:ebcc:89a3 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:b6:9f:ed txqueuelen 1000 (Ethernet)
RX packets 3 bytes 746 (746.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 81 bytes 6462 (6.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1 (Local Loopback)
RX packets 1363 bytes 1359483 (1.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1363 bytes 1359483 (1.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@cham002 ~]# curl -x192.168.100.1:80 test.com/admin/
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.12.1</center>
</body>
</html>
[root@cham002 ~]# cat /tmp/test.com.log
127.0.0.1 - [03/Jan/2018:21:35:36 +0800] test.com "/index.html" 200 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:15:59:16 +0800] test.com "/admin/" 200 "http://www.baidu.com/1.txt" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:00 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:14 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:37 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.100.1 - [04/Jan/2018:16:05:14 +0800] test.com "/admin/" 403 "-" "curl/7.29.0
访问控制(针对正则匹配)
[root@cham002 ~]# vim /usr/local/nginx/conf/vhost/test.com.conf
server
{
listen 80;
server_name test.com test2.com test3.com;
index index.html index.htm index.php;
root /data/wwwroot/test.com;
if ($host != ''test.com'' ) {
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
# location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
# {
# expires 7d;
# access_log off;
# }
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.test.com ;
if ($invalid_referer) {
return 403;
}
access_log off;
}
location ~ .*\.(js|css)$
{
expires 12h;
access_log off;
}
location /admin/
{
allow 127.0.0.1;
allow 192.168.230.135;
deny all;
}
location ~ .*(upload|image)/.*\.php$
{
deny all;
}
access_log /tmp/test.com.log cham;
}
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -s reload
[root@cham002 ~]# mkdir /data/wwwroot/test.com/upload
[root@cham002 ~]# echo "11111" > /data/wwwroot/test.com/upload/1.php
测试
[root@cham002 ~]# curl -x127.0.0.1:80 test.com/upload/1.php
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.12.1</center>
</body>
</html>
[root@cham002 ~]# curl -x127.0.0.1:80 test.com/upload/1.txt
11111
看日志
[root@cham002 ~]# cat /tmp/test.com.log
127.0.0.1 - [03/Jan/2018:21:35:36 +0800] test.com "/index.html" 200 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:15:59:16 +0800] test.com "/admin/" 200 "http://www.baidu.com/1.txt" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:00 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:14 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.230.135 - [04/Jan/2018:16:01:37 +0800] test.com "/admin/" 200 "-" "curl/7.29.0"
192.168.100.1 - [04/Jan/2018:16:05:14 +0800] test.com "/admin/" 403 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:16:15:46 +0800] test.com "/upload/1.php" 403 "-" "curl/7.29.0"
127.0.0.1 - [04/Jan/2018:16:16:46 +0800] test.com "/upload/1.txt" 200 "-" "curl/7.29.0"
针对 user_agent 限制
server
{
listen 80;
server_name test.com test2.com test3.com;
index index.html index.htm index.php;
root /data/wwwroot/test.com;
if ($host != ''test.com'' ) {
rewrite ^/(.*)$ http://test.com/$1 permanent;
}
# location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
# {
# expires 7d;
# access_log off;
# }
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.test.com ;
if ($invalid_referer) {
return 403;
}
access_log off;
}
location ~ .*\.(js|css)$
{
expires 12h;
access_log off;
}
location /admin/
{
allow 127.0.0.1;
allow 192.168.230.135;
deny all;
}
location ~ .*(upload|image)/.*\.php$
{
deny all;
}
if ($http_user_agent ~ ''Spider/3.0|YoudaoBot|Tomato'')
{
return 403;
}
access_log /tmp/test.com.log cham;
}
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -s reload
[root@cham002 ~]# curl -x127.0.0.1:80 test.com/upload/1.txt -I
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 08:22:45 GMT
Content-Type: text/plain
Content-Length: 6
Last-Modified: Thu, 04 Jan 2018 08:16:39 GMT
Connection: keep-alive
ETag: "5a4de2e7-6"
Accept-Ranges: bytes
[root@cham002 ~]# curl -A "Tomatodsfsdf" -x127.0.0.1:80 test.com/upload/1.txt -I
HTTP/1.1 403 Forbidden
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 08:23:37 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
说明: deny all 和 return 403 效果一样
12.15 Nginx 解析 PHP 相关配置
核心配置:
[root@cham002 ~]# vim /usr/local/nginx/conf/vhost/test.com.conf
location ~ \.php$
{
include fastcgi_params;
#fastcgi_pass unix:/tmp/php-fcgi.sock;
fastcgi_pass 127.0.0.1:9000;
##fastcgi_pass两种监听格式,但是要保证Nginx和php-fpm中格式一致
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/wwwroot/test.com$fastcgi_script_name;
}
[root@cham002 ~]# cat /usr/local/php-fpm/etc/php-fpm.conf
[global]
pid = /usr/local/php-fpm/var/run/php-fpm.pid
error_log = /usr/local/php-fpm/var/log/php-fpm.log
[www]
#listen = /tmp/php-fcgi.sock
listen = 127.0.0.1:9000
listen.mode = 666
user = php-fpm
group = php-fpm
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
rlimit_files = 1024
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 ~]# /usr/local/nginx/sbin/nginx -s reload
[root@cham002 ~]# /etc/init.d/php-fpm reload
Reload service php-fpm done
[root@cham002 ~]# curl -x 127.0.0.1:80 test.com/3.php -I
HTTP/1.1 200 OK
Server: nginx/1.12.1
Date: Thu, 04 Jan 2018 10:44:25 GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/5.6.30
注: 在此注意两点,fastcgi_pass 有两种格式,但是无论使用哪种格式都有保证 Nginx 和 php-fpm 中格式一致,否则会报错 502;fastcgi _param SCRIPT _FILENAME 所在行的路径要和 root 路径一致!
12.16 Nginx 代理
Nginx 代理是一种反向代理。反向代理(Reverse Proxy)方式是指以代理服务器来接受 Internet 上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
工作原理
Nginx 代理是在一台代理服务器中自定义一个域名,该域名指向一个 IP,然后将用户的请求通过这台代理服务器访问指定的 IP 所对应的 web 服务器。
graph LR
用户-->代理服务器
代理服务器-->用户
代理服务器-->web服务器
web服务器-->代理服务器
[root@cham002 ~]# cd /usr/local/nginx/conf/vhost
[root@cham002 vhost]# vim proxy.conf
server
{
listen 80;
server_name ask.apelearn.com;
#定义域名(一般和被代理ip的域名保持一致)
location /
{
proxy_pass http://121.201.9.155/;
#指定被代理(被访问)的IP(web服务器IP)
proxy_set_header Host $host;
#$host指的是代理服务器的servername(也是被代理IP的域名)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
说明: 因为该虚拟主机只用作代理服务器,不需要访问本地文件,所以不需要设置根目录。
没有设置代理前
[root@cham002 vhost]# curl -x127.0.0.1:80 ask.apelearn.com/robots.txt
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.12.1</center>
</body>
</html>
[root@cham002 vhost]#
[root@cham002 vhost]# /usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@cham002 vhost]# /usr/local/nginx/sbin/nginx -s reload
设置代理后
[root@cham002 vhost]# curl -x127.0.0.1:80 ask.apelearn.com/robots.txt
#
# robots.txt for MiWen
#
User-agent: *
Disallow: /?/admin/
Disallow: /?/people/
Disallow: /?/question/
Disallow: /account/
Disallow: /app/
Disallow: /cache/
Disallow: /install/
Disallow: /models/
Disallow: /crond/run/
Disallow: /search/
Disallow: /static/
Disallow: /setting/
Disallow: /system/
Disallow: /tmp/
Disallow: /themes/
Disallow: /uploads/
Disallow: /url-*
Disallow: /views/
Disallow: /*/ajax/[root@cham002 vhost]#
6 月 11 日任务 Nginx 防盗链、Nginx 访问控制、Nginx 解析 php 相关配置、Nginx 代理
12.13 Nginx 防盗链
修改配置文件
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip|doc|pdf|gz|bz2|jpeg|bmp|xls)$
{
expires 7d;
valid_referers none blocked server_names *.abc.com ;
if ($invalid_referer) {
return 403;
}
access_log off;
}
测试:
curl -e "http://www.abc.com/" -x127.0.0.1:80 -I abc.com/1.jpg
12.14 Nginx 访问控制
修改配置文件
#按目录匹配
location /
{
allow 127.0.0.1;
deny all;
}
#可以匹配正则
location ~ .*(upload|image)/.*\.php$
{
deny all;
}
#根据 user_agent 限制
if ($http_user_agent ~* ''Spider/3.0|YoudaoBot|Tomato'') // 匹配符号后面 +* 忽略大小写
{
return 403;
}
deny all 和 return 403 效果一样
12.15 Nginx 解析 php 相关配置
location ~ \.php$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass 配置对应的参数 是 sock 还是 ip 否则 502 错误
listen.mode = 666 监听 sock 不定义 mode sock 文件权限 440
12.16 Nginx 代理
1. 新建配置文件 proxy.conf
server
{
listen 80;
server_name 111.com; // 本机域名
location /
{
proxy_pass http://106.39.167.118:80/; // 目标服务器
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
debian10+Nginx+Flask+uWSGI+uWSGI Emperor配置流程
之前写过 debian8 和 debian9 的配置文章,现在升级到了 debian10,那就重新调整一下安装过程.
debian9+flask+uWSGI+uWSGI Emperor 配置流程
Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项
查看系统相关信息
debian
版本号
cat /etc/issue
python
及 GCC
版本号
python3
pip
版本号
pip3 -V
安装 uwsgi
注意,有的同学会提前安装好项目的 python
虚拟环境,但这里不是在虚拟环境里安装的,是在根目录环境安装 uwsgi
:
pip install uwsgi
安装 nginx
我用的是 oneinstack
一键脚本。可以百度找一下。
注意:文章所有 xxx.com
地方均需要改为自己的域名或文件夹路径。
通过自带功能新增域名映射文件存放路径:
/data/root/xxxx.com
安装 Flask
创建虚拟环境
使用python3
自带的venv
命令虚进行创建虚拟环境。以下命令中,第二个venv
是文件夹名称:
cd /data/root/xxxx.com
python3 -m venv venv
其它虚拟环境也可以,大家可以自由选择, 比如 virtualenv
。
安装 Flask
进入虚拟环境:
source venv/bin/activate
通过 pip
命令进行安装flask
:
pip3 install flask
新建 uWSGI
配置文件
创建一个新的 uWSGI
配置文件/data/root/xxx.com/xxx.com_uwsgi.ini
:
[uwsgi]
#指向网站跟目录,应用程序的文件夹路径 application''s base folder
base = /data/root/xxx.com
# 按字面意思是python的环境变量路径,写的是网站根目录
# 给PYTHONPATH 增加一个目录(或者一个egg),你可以最多使用该选项64次。
# 给PYTHONPATH python-path pp 这三个是相同作用
pythonpath = %(base)
# 虚拟目录,设置PYTHONHOME/virtualenv
home = %(base)/venv
# 指定监听文件,修改后重新打开日志
# 如果修改/碰了指定的文件,那么触发日志的重新打开
touch-logreopen = /data/logs/uwsgi/.touchforlogrotate
#使进程在后台运行,并将日志打到指定的日志文件或者udp服务器。
#这个指令会让uWSGI在后台运行并将日志打到 /data/logs/uwsgi/的对应文件中。
daemonize = /data/logs/uwsgi/%n.log
#日志文件的路径 location of log files
; logto = /data/logs/uwsgi/%n.log
#加载指定的python WSGI模块(模块路径必须在PYTHONPATH里)
module = app
# 设置在收到请求时,uWSGI加载的模块中哪个变量将被调用,默认是名字为“application”的变量。
callable = app
#socket文件的路径 socket file''s location
socket = %(base)/tmp/%n.sock
#pchmod-socket的权限 ermissions for the socket file
chmod-socket = 666
# 处理器数
processes = 2
# 线程数
1threads = 2
#您需要的是,reload-mercy是用作回退的全局值。
#what you need, reload-mercy is a global value used as a fallback
#--reload-mercy-在重新加载/停止整个uWSGI实例时使用
#--worker-reload-mercy-在重新加载/停止单个工作程序时使用
worker-reload-mercy = 10
# 修改代码时,自动重启uwsgi服务,每1秒检查一次
python-autoreload = 1
# 这个选项会设置harakiri超时时间(可以看wiki首页的相关内容)。如果一个请求花费的时间超过了这个harakiri超时时间,那么这个请求都会被丢弃,并且当前处理这个请求的工作进程会被回收再利用(即重启)。
# 这个设置会使uwsgi丢弃所有需要60秒才能处理完成的请求。
harakiri = 60
按照实际情况修改文件中的路径。
创建日志文件夹
创建一个新文件夹存放uWSGI日志,更改文件夹的所有权(因为我是用 oneinstack
脚本创建的文件夹,默认用户组是www:www
,所以相关文件夹拥有者权限也是给了www:www
):
mkdir -p /data/logs/uwsgi
chown -R www:www /data/logs/uwsgi
配置网站的nginx配置文件
在原有的域名conf
配置文件中添加以下内容:
location / {
try_files $uri @yourapplication;
}
location @yourapplication {
include uwsgi_params;
uwsgi_pass unix:/data/root/xxx.com/tmp/xxx.com_uwsgi.sock;
}
配置uWSGI Emperor
使用uWSGI Emperor
管理多个 uwsgi
。uWSGI Emperor
是用来管理uwsgi
后台运行的。
新建/etc/systemd/system/emperor.uwsgi.service
文件,代码如下:
[Unit]
Description=uWSGI Emperor
After=syslog.target
[Service]
#uwsgi 服务的路径,以及需要启动的 ini 文件路径,根据自己的实际情况进行修改
ExecStart=/usr/local/bin/uwsgi --ini /etc/uwsgi/emperor.ini
# Requires systemd version 211 or newer
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
创建/etc/uwsgi
文件夹
mkdir /etc/uwsgi
创建文件/etc/uwsgi/emperor.ini
:
touch /etc/uwsgi/emperor.ini
里面代码如下:
[uwsgi]
emperor = /etc/uwsgi/vassals
uid = www
gid = www
把网站的uwsgi.ini
文件要给个软链,加到/etc/uwsgi/vassals/
文件夹中:
mkdir /etc/uwsgi/vassals
ln -s /data/root/xxx.com/xxx.com_uwsgi.ini /etc/uwsgi/vassals
在/etc/uwsgi/emperor.ini
文件里,设置了文件所有者是 www:www
,我们要给对应的文件夹和文件做所有者权限修改(这一步根据实际情况来判断是否需要):
chown -R www:www /data/root/xxx.com
chown -R www:www /data/logs/uwsgi/
至此,配置已经完成。
相关命令
启动服务
systemctl start emperor.uwsgi.service
检查状态
systemctl status emperor.uwsgi.service
你会看到提示:
emperor.uwsgi.service - uWSGI Emperor
Loaded: loaded (/etc/systemd/system/emperor.uwsgi.service; disabled; vendor preset: enabled)
Active: active (running) since Mon 2022-10-31 23:55:52 CST; 3s ago
Main PID: 27634 (uwsgi)
Status: "The Emperor is governing 0 vassals"
Tasks: 1 (limit: 3549)
Memory: 3.4M
CGroup: /system.slice/emperor.uwsgi.service
└─27634 /usr/local/bin/uwsgi --ini /etc/uwsgi/emperor.ini
Oct 31 23:55:52 giaogiao uwsgi[27634]: *** WARNING: you are running uWSGI without its master process manager ***
Oct 31 23:55:52 giaogiao uwsgi[27634]: your processes number limit is 11830
开机启动
systemctl enable emperor.uwsgi.service
其它命令
systemctl start emperor.uwsgi.service
systemctl stop emperor.uwsgi.service
systemctl status emperor.uwsgi.service
Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项
Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项
Debian8 使用 uWSGI Emperor
和 Debina7 是不一样的。相关问题,可以直接查看本篇文章的第4步。
注意:本篇文章是在服务器中用 root 账号执行的。文章主要讲相关配置文件,安装方法请自寻。
-----更新------
2017年9月8日更新:更正运行服务的代码
1.uWSGI
配置文件 /home/luejiao.com/luejiao_uwsgi.ini
[uwsgi]
# 指向网站目录
base = /home/luejiao.com
# 启动文件
wsgi-file = run.py
module = app
# 虚拟目录
home = %(base)/flask
# 按字面意思是python的环境变量路径,写的是网站根目录
pythonpath = %(base)
#socket文件的路径 socket file''s location
socket = /home/luejiao.com/tmp/%n.sock
#pchmod-socket的权限 ermissions for the socket file
chmod-socket = 644
#the variable that holds a flask application inside the module imported at line #6
callable = app
#日志文件的路径 location of log files
logto = /wwwlogs/uwsgi/%n.log
# 处理器数
processes = 4
# 线程数
1threads = 2
# 修改代码时,自动重启uwsgi服务
python-autoreload=1
2.新建保存日志的文件夹,并赋权
mkdir -p /wwwlogs/uwsgi
chown -R www:www /wwwlogs/uwsgi
3.在网站的 nginx conf 配置文件中,添加:
location / {
try_files $uri @yourapplication;
}
location @yourapplication {
include uwsgi_params;
uwsgi_pass unix:/home/luejiao.com/tmp/luejiao_uwsgi.sock;# 这里注意替换成自己的socket文件路径
}
下面是重头戏,debian8 和 debian7 在配置 uWSGI Emperor
是不一样的!!!
debian7 是把配置文件放到 /etc/init/uwsgi.conf
,而在 debian8 中,是放到 /etc/systemd/system/
中的。
本文章是讲 debian8 的环境下配置 uWSGI Emperor
。 官方对应文档
4.新建/etc/systemd/system/emperor.uwsgi.service
文件,代码如下:
[Unit]
Description=uWSGI Emperor
After=syslog.target
[Service]
#uwsgi 服务的路径,以及需要启动的 ini 文件路径,根据自己的实际情况进行修改
ExecStart=/usr/local/bin/uwsgi --ini /etc/uwsgi/emperor.ini
# Requires systemd version 211 or newer
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
5.上述代码中,/etc/uwsgi/emperor.ini
文件的代码如下:
[uwsgi]
emperor = /etc/uwsgi/vassals
uid = www
gid = www
6.把网站的 uwsgi.ini 文件要给个软链,加到 /etc/uwsgi/vassals/
文件夹中:
mkdir /etc/uwsgi && mkdir /etc/uwsgi/vassals
ln -s /home/luejiao.com/luejiao_uwsgi.ini /etc/uwsgi/vassals
7.在第5步中的文件夹中,设置了文件所有者是 www:www
,我们要给对应的文件夹和文件做所有者权限修改(这一步根据实际情况来判断是否需要):
chown -R www:www /home/luejiao.com
chown -R www:www /var/log/uwsgi/
8.运行服务、停止服务、状态查询:
debian7 开启服务的代码是:service uwsgi start
debian8 的代码是
systemctl start emperor.uwsgi.service
systemctl stop emperor.uwsgi.service
systemctl status emperor.uwsgi.service
End!
今天的关于Nginx + uWSGI + Python + Django构建必应高清壁纸站的分享已经结束,谢谢您的关注,如果想了解更多关于12.13 Nginx 防盗链 12.14 Nginx 访问控制 12.15 Nginx 解析 php 相关配置 12.16 Nginx 代理、6 月 11 日任务 Nginx 防盗链、Nginx 访问控制、Nginx 解析 php 相关配置、Nginx 代理、debian10+Nginx+Flask+uWSGI+uWSGI Emperor配置流程、Debian8 + Flask + Nginx + uWSGI + uWSGI Emperor 基本配置文件注意事项的相关知识,请在本站进行查询。
本文标签: