一、理论基础部分
1.web服务工作流程
在搭建开始前,我们先来梳理下web服务工作流程,先看下图:
1、用户(PC)向web服务器发起http请求
2、web服务器判断用户请求文件是否为静态文件,是则直接读取静态文件并返回给用户,不是则通过WSGI协议将请求丢给web框架(django)代码处理
3、看web框架是否启动django中间件,如果启用,则依据中间件对请求进行修改,如果不启用,则进入下一步
4、web框架中的路由程序将根据请求中的url文件名将请求路由至相应py文件
5、相应py文件收到请求后根据用户提交的参数进行计算(期间可能会调用数据库),然后返回计算后的结果和自定义头部信息以及状态码返回
6、web框架将返回的数据打上通用标识符(头部信息)后返回给web服务器
7、web服务器打上web服务器的通用标识符(头部信息)后返回给用户
8、用户收到返回的数据
2. wsgi协议是啥
Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口
通过上面可以看到django框架基于WSGI协议和web服务器进行交互,那么WSGI协议又是什么呢? 咱们用代码来说明(伪代码。写一个简易的遵循WSGI协议的web服务器软件和django程序):
3.django的简易WSGI服务器的程序:
class WSGI_WEB(object):
def __init__(self):
# 1. 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 2. 绑定
self.tcp_server_socket.bind(("", 7890))
# 3. 变为监听套接字
self.tcp_server_socket.listen(128)
def set_response_header(self, status, headers):
self.status = status
self.headers = [("server", "WSGI_simple_web v1.0")]
self.headers += headers
def run(self):
new_socket, client_addr = self.tcp_server_socket.accept()
env = new_socket.recv(1024)
body = application(env, set_response_header) # env是web服务器接收到浏览器发送来的数据包;set_response_header为web服务器的一个方法地址,目的是让django帮web服务器生成http头部(不是以return的形式给web服务器);此外还有这里调用django里的应用还有一个最核心的任务,就是获取返回数据的body!
header = self.status + self.headers
response = header + body
new_socket.send(response.encode("utf-8"))
4. django的app程序:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"]
5. 问题及解决:
在生产环境中使用django提供的简易web服务器性能太差,一般只用于调试。强大的nginx又不支持WSGI,那么怎么办呢?
6. 解决方案:
在nginx和python应用之间加一层支持WSGI协议的web服务器。以后静态文件由nginx进行处理,动态文件丢给WSGI服务器,然后WSGI服务器再丢给web框架处理。最理想的支持WSGI协议的web服务器就是uWSGI。
下面来详细介绍下搭建uWSGI服务器以及与nginx联动的方法:
二、安装及配置uWSGI
0、首先:python3安装并创建虚拟环境
【详见】https://blog.csdn.net/u010132177/article/details/105702099
1、创建及使用虚拟环境(便于安装多个网站)
1.安装虚拟环境
pip3 install --upgrade virtualenv
2.在根目录创建一个www目录并在其中创建环境
cd /
mkdir www
cd www #进入www目录创建
mkdir web1
cd web1
3.创建基于python3的虚拟环境放在/www/web1/.env目录下(.开头的文件夹是隐藏的)
virtualenv -p python3 .env
4.进入虚拟环境
source .env/bin/activate
5. 进入虚拟环境后,可安装例如django/flask安装django
(在腾讯云或阿里服务器上已经默认配置了国内pip源所以不用另行配置,速度即很快)
pip3 install django==2.1.8 #centos里因为sqlite版本问题不能安装最新django
#详见:https://www.cnblogs.com/hszstudypy/p/11512244.html
6.在本地创建一个测试项目,然后进入项目根目录把所有内容传到刚在www/web1/建好的文件夹下
django-admin startproject web1
7.布署前需要关闭调试、允许任何机器访问,打开 /项目名/项目名/settings.py改如下地方
DEBUG = False
ALLOW_HOSTS=['*',]
8.上传完成运行项目放在8080端口:(0.0.0代表在当前ip创建运行)
python manage.py runserver 0.0.0.0:8080
9.然后在浏览器打开 12.15.18.122:8080即可看到火箭发射成功效果(ip换成你自己服务器ip)
运行完成后,证明项目正常,即可关闭自带wsgi服务,ctrl+c
10.退出虚拟环境
deactivate
附件1:django测试项目下载
https://download.csdn.net/download/u010132177/12367228
附件:安装项目的依赖包及部分实战
上传项目后安装django项目的需要的包
pip3 freeze > plist.txt
pip3 install -r plist.txt
[root@VM_0_11_centos /]# cd dailyfresh
[root@VM_0_11_centos var]# ll
...此处列出所有文件详情略过
[root@VM_0_11_centos var]# mkdir dailyfresh
[root@VM_0_11_centos var]# cd dailyfresh
[root@VM_0_11_centos web1]# pwd
/var/web1
[root@VM_0_11_centos web1]# virtualenv -p python3 .env
created virtual environment CPython3.7.3.final.0-64 in 226ms
creator CPython3Posix(dest=/var/web1/.env, clear=False, global=False)
seeder FromAppData(download=False, pip=latest, setuptools=latest, wheel=latest, via=copy, app_data_dir=/root/.local/share/virtualenv/seed-app-data/v1.0.1)
activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator
[root@VM_0_11_centos web1]# source .env/bin/activate
(.env) [root@VM_0_11_centos web1]#
显示以上表示进入虚拟环境成功(.env)接下来就可以进行其它配置了
2、安装uWSGI替换django的自带简写wsgi服务
0) 在虚拟环境继续安装uwsgi
1.在虚拟环境下继续安装uwsgi
pip3 install uwsgi
2)在项目根目录下建立文件www/web1/uwsgi.ini
[uwsgi]
#使用nginx连接时使用
#socket=0.0.0.0:8080 #本地127.0.0.1
#直接做web服务器使用 python manage.py runserver ip:port
http=0.0.0.0:8080
#项目目录(pwd查看当前项目路径并放于此处)
chdir=/www/web1
#项目中wsgi.py文件的目录,相对于项目目录
wsgi-file=web1/wsgi.py
#指定启动的工作进程数
processes=4
#指定工作进程中的线程数
threads=2
master=True
#保存启动之后主进程的pid
pidfile=uwsgi.pid
#设置uwsgi后台运行,uwsgi.log保存日志信息
daemonize=uwsgi.log
#设置虚拟环境的路径
virtualenv=/www/web1/.env
3)启动uwsgi服务
su ztjt #真正运行时最好换到非root用户执行,否则可能有渗透后直接被黑客拿到root权限风险
uwsgi --ini uwsgi.ini #启动服务
ps ajx|grep uwsgi #查看正在运行中的uwsgi进程
附1:执行实时记录
(.env) [root@VM_0_11_centos web1]# pwd
/www/dailyfresh
1.查看有没有其它的uwsgi进程:
(.env) [root@VM_0_11_centos web1]# ps ajx|grep uwsgi
1 4397 4396 4396 ? -1 S 0 0:04 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4573 4396 4396 ? -1 Sl 0 0:29 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4574 4396 4396 ? -1 Sl 0 0:31 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4575 4396 4396 ? -1 Sl 0 0:29 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4576 4396 4396 ? -1 Sl 0 0:34 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4577 4396 4396 ? -1 Sl 0 0:31 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
4397 4578 4396 4396 ? -1 S 0 0:00 /var/web1/.env/bin/uwsgi --ini uwsgi.ini
11564 20028 20027 11564 pts/0 20027 R+ 0 0:00 grep --color=auto uwsgi
2.关闭无用的进程(指名路径)
uwsgi --stop /var/web1/uwsgi.pid
3.启动服务(相当于django自带的run server)
(.env) [root@VM_0_11_centos dailyfresh]# uwsgi --ini uwsgi.ini
[uWSGI] getting INI configuration from uwsgi.ini
4.查看进程,正确效果如下:
(.env) [root@VM_0_11_centos dailyfresh]# ps ajx|grep uwsgi
1 20690 20689 20689 ? -1 S 0 0:00 uwsgi --ini uwsgi.ini
20690 20692 20689 20689 ? -1 Sl 0 0:00 uwsgi --ini uwsgi.ini
20690 20693 20689 20689 ? -1 Sl 0 0:00 uwsgi --ini uwsgi.ini
20690 20694 20689 20689 ? -1 Sl 0 0:00 uwsgi --ini uwsgi.ini
20690 20695 20689 20689 ? -1 Sl 0 0:00 uwsgi --ini uwsgi.ini
11564 20811 20810 11564 pts/0 20810 R+ 0 0:00 grep --color=auto uwsgi
成功效果:输入网址:http://你的服务器ip:8080,但如果有样式、图片等静态资源会不能正确显示,因此要进行第三步配置nginx
至此uwsgi配置完成,
附:uwsgi常用命令
uwsgi --ini uwsgi.ini # 启动(最后部分代表文件名)
uwsgi --reload uwsgi.pid # 重启
uwsgi --stop uwsgi.pid # 关闭
cat uwsgi.log #查看日志信息
ps ajx|grep uwsgi #查看正在运行中的uwsgi进程
uwsgi --stop /var/web1/uwsgi.pid #如果有其它的uwsgi进程则可关闭其它目录下的项目
killall -s INT uwsgi #关闭所有uwsgi的进程(用于stop时找不到id的情况)
找到uwsgi的安装路径
find / -name uwsgi
#/usr/local/python3/bin/uwsgi
#/var/web1/.env/bin/uwsgi
把上步获取到的两个路径创建软链接(类似环境变量)
ln -s /usr/local/python3/bin/uwsgi
#adduser www
#passwd www
#更改用户 www的密码 。
#新的 密码:
#无效的密码: 密码未通过字典检查 - 过于简单化/系统化
#重新输入新的 密码:
创建www用户组和用户
groupadd www
useradd -g www pythoner
su www 进入新建的账户即可进行以下步骤
2步方法的其它方式(可跳过)
a.方法一(命令行方法):
【注意】执行以下二个命令的时候:一定要在你要部署的项目目录中。ip换成你自己的服务器IP
测试启动自己写个小项目看效果:
uwsgi --http 182.182.287.85:8001 --wsgi-file index.py
或简写成:
uwsgi --http :8001 --wsgi-file index.py
================成功效果如下:================================
uwsgi --http :8001 --wsgi-file index.py
*** Starting uWSGI 2.0.18 (64bit) on [Sat Apr 25 14:40:03 2020] ***
detected binary path: /var/web1/.env/bin/uwsgi
...
200) 1 headers in 44 bytes (1 switches on core 0)
然后访问网页:xxx.xxx.xxx.xxx:8001
输出 helloworld 即成功!
真正启动项目时
uwsgi --http 192.168.31.123:80 --file web1/wsgi.py --static-map=/static=static
或简写成:
uwsgi --http :80 --file web1/wsgi.py --static-map=/static=static
命令的含义是:在你的服务器的ip地址的80端口通过wsgi.py文件来提供服务,你的项目静态文件放在/static目录中
相关参数详细意义如下:
--http 监听IP端口
--file 项目wsgi.py文件路径
--static-map 静态文件路径
b.uwsgi.ini配置文件其它功能说明:
uwsgi.ini配置文件:vi uwsgi.ini
[uwsgi]
# 监听端口(nginx采用反向代理模式时必填此处和nginx.conf里有对应)
http = 0.0.0.0:8001
# 项目目录
chdir=/var/web1/
# 启动uwsgi的用户名和用户组
uid=root
gid=root
# 指定项目的application(我猜是这里的“test1.wsgi”拼接上面的项目目录后,就将项目中的wsgi.py文件和uWSGI服务器关联起来了)
module=web1.wsgi:application
# 指定sock的文件路径(nginx采用本地模式时必填)
socket=/var/web1/uwsgi.sock
# 启用主进程
master=true
# 进程个数
workers=5
pidfile=/var/web1/uwsgi.pid
# 自动移除unix Socket和pid文件当服务停止的时候
vacuum=true
# 序列化接受的内容,如果可能的话
thunder-lock=true
# 启用线程
enable-threads=true
# 设置自中断时间
harakiri=30
# 设置缓冲
post-buffering=4096
# 设置日志目录
daemonize=/var/web1/uwsgi.log
# 设置隔多久加载一次项目代码
py-autoreload=1
然后,执行配置文件即可启动服务
【注意】这里用什么账户执行的,如果黑客渗透进来获取到的就是什么账户。
所以这一步切忌不要用root执行(用root也可运行但有风险)
uwsgi --ini uwsgi.ini
三、安装及nginx基础配置
详见:https://blog.csdn.net/u010132177/article/details/105704352
0)修改配置/www/web1/uwsgi.ini
[uwsgi]
1.使用nginx连接时使用,则2步注释掉(与2步2选1)
socket=0.0.0.0:8080 #本地127.0.0.1
2.直接做web服务器使用 python manage.py runserver ip:port
#http=0.0.0.0:8080
...
1)首先进入nginx目录及常用命令
find / -name nginx
/opt/nginx
/opt/nginx/sbin/nginx
cd /opt/nginx/conf
或直接编辑
vi /opt/nginx/conf/nginx.conf
===【nginx常用命令】====================
0.查看nginx服务是否已打开
ps ajx|grep nginx
1.启动nginx服务
sbin/nginx
或在其它目录
/opt/nginx/sbin/nginx
2.停止nginx服务
sbin/nginx -s stop
或在其它目录
/opt/nginx/sbin/nginx -s stop
3.重启
/opt/nginx/sbin/nginx -s reload
打开网页:你服务器ip:80 显示welcome ...
2)编辑nginx.conf文件,在server节点下添加新的location项,指向uwsgi的socket=0.0.0.0:8080的ip与端口。
location / {
#1.将所有的参数转到uwsgi下
include uwsgi_params;
#2.uwsgi的ip与端口
uwsgi_pass 0.0.0.0:8080;
}
3)重启uwsgi和nginx
/opt/nginx/sbin/nginx -s reload
uwsgi --reload uwsgi.pid
效果:打开http://x.x.x.x/index即可看到输出helloworld
四、nginx配置静态文件相关基础配置
1)打开conf/nginx.conf文件。
vi /opt/nginx/conf/nginx.conf
2)在server节点下添加新的location项,用于处理静态文件。
location /static {
alias /www/web1/static/;
}
3)在服务器上创建如下目录。
sudo mkdir -vp /www/web1/static/
4) 修改目录权限。
sudo chmod 777 /www/web1/static/
5)修改test6/settings.py文件。
STATIC_ROOT='/var/www/test6/static/'
STATIC_URL='/static/'
6)收集所有静态文件到static_root指定目录。
python manage.py collectstatic
按提示输入yes,收集文件。
7))停止后再启动nginx服务。
8)在浏览器中刷新,即可看到图片样式等静态文件正确显示(至此基础配置完成)
五、nginx进阶配置(可选)
方法一(反向代理模式):
编辑文件:vi nginx.conf
upstream uwsgi{
server 10.10.10.29:8888;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
proxy_pass http://uwsgi; # 通过反向代理和uWSGI服务器关联
}
}
方式二(本地模式):
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
include uwsgi_params; # 指定nginx和uWSGI服务器的通信方式
uwsgi_connect_timeout 30;
uwsgi_pass unix:/opt/test/script/uwsgi.sock; # 通过sock文件和uWSGI服务器关联! 因为nginx会去读取.sock文件,所以需要关闭selinux才行!!!
}
}
4、动静分离
此时访问django的admin管理后台时,静态资源会调取失败。这时可以将该项目所有静态资源统一收集到一个文件夹下,然后由nginx统一去调取,真正做到动静分离(动的给uWSGI,静的由nginx直接调取):
1.在settings.py中加入:
TATIC_ROOT = os.path.join(BASE_DIR, 'static_file')
2.执行如下命令(搜集项目中所有静态文件至’static_file’目录):
python3.6 manage.py collectstatic --noinput
【结果】此时会在项目目录下生成一个’static_file’文件夹,内含admin和所有app涉及的静态文件。
5、反向代理设置
在nginx中配置静态文件路径(如果nginx和uWSGI不属同一台服务器可以使用反向代理的方式来调取静态文件):
location /static/ {
alias /opt/test/test1/static_file/;
}
此时就可以访问基于python后台的web网站了
附:新建的用户加权限
个人用户的权限只可以在本home下有完整权限,其他目录要看别人授权。而经常需要root用户的权限,这时候sudo可以化身为root来操作。我记得我曾经sudo创建了文件,然后发现自己并没有读写权限,因为查看权限是root创建的。
新创建的用户并不能使用sudo命令,需要给他添加授权。
sudo命令的授权管理是在sudoers文件里的。可以看看sudoers:
[root@localhost ~]# sudoers
bash: sudoers: 未找到命令...
[root@localhost ~]# whereis sudoers
sudoers: /etc/sudoers /etc/sudoers.d /usr/libexec/sudoers.so /usr/share/man/man5/sudoers.5.gz
找到这个文件位置之后再查看权限:
[root@localhost ~]# ls -l /etc/sudoers
-r--r----- 1 root root 4251 9月 25 15:08 /etc/sudoers
是的,只有只读的权限,如果想要修改的话,需要先添加w权限:
[root@localhost ~]# chmod -v u+w /etc/sudoers
mode of "/etc/sudoers" changed from 0440 (r--r-----) to 0640 (rw-r-----)
然后就可以添加内容了,在下面的一行下追加新增的用户:
[root@localhost ~]# vim /etc/sudoers
## Allow root to run any commands anywher
root ALL=(ALL) ALL
linuxidc ALL=(ALL) ALL #这个是新增的用户
wq保存退出,这时候要记得将写权限收回:
[root@localhost ~]# chmod -v u-w /etc/sudoers
mode of "/etc/sudoers" changed from 0640 (rw-r-----) to 0440 (r--r-----)
这时候使用新用户登录,使用sudo:
[linuxidc@localhost ~]$ sudo cat /etc/passwd
[sudo] password for linuxidc:
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
参考文章:
https://www.cnblogs.com/shendeng23/p/10466736.html
https://www.cnblogs.com/ccqk/p/11260792.html
https://blog.csdn.net/qq_42314550/article/details/81805328