*记:基于Centos+uWSGI+Nginx部署web应用
碎碎念
- 最近在给手里在做的几个python web应用统一配置云服务器。期间涉及的配置步骤和一些通信概念还是比较多,而且网上提供的方法大多都不是很有效,鱼龙混杂。故写篇文章详细记录一下过程,整合一些可信且有效的信息来源,方便乘凉/提前周更。
- 本文是对 在基于Centos系统的云服务器上配置python web 的一个简略的过程记录,此外还包括了django的产品环境配置,以及对python web通信协议WSGI,nginx代理服务器等概念的介绍。
【1】
在Centos上进行python配置
- 安装python3.6版本。切记不能动原有的python2环境(centos系统运行依赖该环境)。
$ yum -y install python36 python36-devel
- 创建虚拟环境pyweb,用于web应用程序的运行。
$ cd /opt$ python3.6 -m venv pyweb
- 为其安装库依赖,requirements.txt 中是一些常用的第三方包,可以自己定义。
$ source /opt/pyweb/bin/activate(pyweb)$ pip install --upgrade pip setuptools
(pyweb)$ vi /opt/pyweb/requirements.txtdjango==3.1.5djangorestframework==3.12.2django-allauth==0.44.0django-cors-headers==3.7.0django-rest-auth==0.9.5django-filter==2.4.0coreapi==2.3.3numpy==1.19.5pymysql==1.0.2joblib==1.0.0pandas==1.1.5sklearnpillow==8.2.0
(pyweb)$ pip install -r /opt/pyweb/requirements.txt
uwsgi安装
- 当构建uWSGI时,需要使用到C编译器,如gcc或clang。如下:
(pyweb)$ yum install gcc -y
(pyweb)$ pip install uwsgi==2.0.19
MYSQL数据库配置
- 数据库安装,并配置其服务端开机启动。
$ sudo dnf install @mysql
$ sudo systemctl enable --now mysql
- 设置数据库密码安全。
$ sudo mysql_secure_installation
- 启动数据库客户端并为服务器创建数据库。
$ mysql -u root -p
- 安全起见,也可以创建一个用户tester,并开启其只能读写dbtest数据库的权限。
mysql> create database dbtest;mysql> create user 'tester'@'%' identified by '******';mysql> grant all privileges on dbtest.* to 'tester'@'%';
NGINX安装
- 在下述位置写入一个nginx.repo文件。
$ vi /etc/yum.repos.d/nginx.repo[nginx]name=nginx repobaseurl=http://nginx.org/packages/centos/7/$basearch/gpgcheck=0enabled=1
- 安装并配置其开机启动。
$ yum -y install nginx$ systemctl enable nginx
【2】
settings环境配置
- 以下修改在本地进行即可。
- 修改settings.py文件为settings文件目录,方便本地和产品环境的切换。如下目录中,base.py即为原settings.py文件。其上覆盖两个文件,local.py用于本地测试环境,pro.py用于生产环境。
settings/__init__.pybase.pylocal.pypro.py
- 修改base.py中的BASE_DIR配置。
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(os.path.join(__file__, os.pardir))))
- 配置local.py
from .base import *DEBUG = TrueDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}}
- pro.py
from .base import *DEBUG = FalseADMINS = (('zixun HUANG', '[email protected]'),)ALLOWED_HOSTS = ['*']DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'dbtest','OPTIONS': {'charset': 'utf8mb4',},'USER':'tester','PASSWORD':'******','HOST':'127.0.0.1','PORT':3306,'CHARSET':'utf8'}}# REDIS_HOST = 'localhost'# REDIS_PORT = 6379# REDIS_DB = 0
- __init__.py
import pymysqlpymysql.install_as_MySQLdb()
静态数据集的收集
- 编辑base.py中的STATIC_ROOT,并注释掉STATICFILES_DIRS,否则导出django的静态数据集会失败。
STATIC_URL = '/static/'# STATICFILES_DIRS = (# os.path.join(BASE_DIR, "static"),# )STATIC_ROOT= os.path.join(BASE_DIR, "static")
- 导出静态数据集,该命令会在你的项目目录中创建一个静态文件目录。之后会配置NGINX直接服务于这些静态文件。
(pyweb)$ python manage.py collectstatic --settings=\your_project_name.settings.base
CSRF和跨域配置
- 编辑base.py文件。
INSTALLED_APPS += ['corsheaders',]MIDDLEWARE += ['corsheaders.middleware.CorsMiddleware',]CORS_ALLOW_CREDENTIALS = TrueCORS_ORIGIN_ALLOW_ALL = TrueCORS_ORIGIN_WHITELIST = ('http://*.*.*.*:*',)CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',)CORS_ALLOW_HEADERS = ('XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma',)
在云服务器同步数据库
- 如果已经在本地makemigrations,则将文件用xftp拷贝至云服务器后。直接migrate即可。
- 该步骤要注意文件目录的管理,笔者在根目录下新建了mysites文件夹用于web应用的管理。
(pyweb)$ python manage.py makemigrations --settings=your_project_name.settings.local
(pyweb)$ python manage.py migrate --settings=your_project_name.settings.pro
【3】
WSGI,uWSGI,uwsgi简单说明
- WSGI全称为Web Server Gateway Interface,是为python语言定义的一种描述web server如何与web application通信的规范。以下内容摘自PEP 3333:
- The WSGI interface has two sides: the "server" or "gateway" side, and the "application" or "framework" side. The server side invokes a callable object that is provided by the application side. The specifics of how that object is provided are up to the server or gateway.
- 在WSGI通信协议中:web server负责从客户端接收request,并转发给web application。接收web application返回的response,并返回给客户端。web application接收由server转发的request,处理请求,并把处理结果response发送给server。
- WSGI协议解决了server与application之间互相限制的问题。即可以选择任意实现了WSGI application的框架(如django,flask),和任意实现了WSGI server协议的服务器(如uWSGI,Gunicorn)。
- uwsgi和WSGI一样,也是一种通信协议。其为uWSGI自有协议,用于定义传输信息的类型,用于与nginx等代理服务器通信。
- uWSGI即为实现了WSGI和uwsgi两种协议的Web服务器。
使用uwsgi.ini配置文件启动项目
- 新建config文件夹和tmp文件夹处于settings的上一级目录,也就是和manage.py处于同一级目录。在config文件夹中新建uwsgi.ini文件。
$ vi /your_absolute_path/config/uwsgi.ini[uwsgi]# https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.htmlchdir=/your_absolute_path/module=your_project_name.wsgi:applicationenv = DJANGO_SETTINGS_MODULE=your_project_name.settings.pro#the local unix socket file than commnuincate to Nginxsocket=%(chdir)tmp/uwsgi.sockprocesses = 8workers=5procname-prefix-spaced=your_project_namepy-autoreload=1http=0.0.0.0:8082uid=rootgid=rootmaster=truevacuum=truethunder-lock=trueenable-threads=trueharakiri=30post-buffering=4096daemonize=%(chdir)tmp/uwsgi.logpidfile=%(chdir)tmp/uwsgi.pid
- 运行uWSGI,该命令需要在之前配置的pyweb环境下进行。停止该进程为--stop相应pid文件。
(pyweb)$ uwsgi --ini config/uwsgi.ini
- 但页面显示无静态文件加载。可在uwsgi.ini中添加如下配置:
for =static mediastatic-map=/static=%(chdir)/%(_)endfor =
Nginx简单介绍
- Nginx是一款轻量级的Web服务器/反向代理服务器,其启动快,内存占用少,高并发能力强。套娃分享一篇文章:https://zhuanlan.zhihu.com/p/34943332。
使用nginx配置文件启动uwsgi
- Nginx可以更高效的提供静态文件,并将动态请求转发给uWSGI worker。此外还可以利用其配置反向代理,负载均衡等来提高服务器性能。
vi /your_absolute_path/config/nginx.confupstream app_name{server unix:/your_absolute_path/tmp/uwsgi.sock;}server{listen 8081;server_name your_server_name;access_log /var/log/nginx/access.log;charset utf-8;gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream;error_page 404 /404.html;error_page 500 502 503 504 /50x.html;location / {include /etc/nginx/uwsgi_params;uwsgi_connect_timeout 20;uwsgi_pass app_name;}location /static {alias /your_absolute_path/static;}location /media {alias /your_absolute_path/media;}}
$ vi /etc/nginx/nginx.confhttp {......# Load modular configuration files from the /etc/nginx/conf.d directory.include /etc/nginx/conf.d/*.conf;include /your_absolute_path/config/*.conf;......server {......}}
- 运行nginx,或重新加载/重启。
service nginx start/reload/restart
- 访问8081端口,已经可以正常访问该页面。此外可以注释掉8082和80端口的页面(分别在uwsgi.ini文件和nginx主配置文件中)。
nginx worker对media目录的访问权限
- 分别运行以下命令,可查看nginx和uWSGI的worker权限:
$ ps -ef|grep nginx
$ ps -ef|grep uWSGI
- 可以看到,uWSGI的worker用户为root(在uwsgi.ini文件中已进行配置)。而nginx worker的用户默认为nginx,该用户对media目录没有读权限(该目录指向root用户)。通过以下命令,对nginx worker赋权:
chown -R nginx:nginx /your_absolute_path/static/chmod -R ug+r /your_absolute_path/static/chown -R nginx:nginx /your_absolute_path/media/chmod -R ug+r /your_absolute_path/media/
SSL安全连接配置
- HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。如果没有配置ssl的话,是无法通过https对站点进行访问的。只能通过http进行访问。
- 编辑nginx.conf主配置文件,修改server 443 ssl中的两个文件路径配置为自己域名的ssl证书以及密钥的路径即可:
......ssl_certificate "/etc/pki/nginx/yours.crt";ssl_certificate_key "/etc/pki/nginx/private/yours.key";......
- 重启nginx代理服务器。
service nginx restart
- 之后为django代码中的settings/pro.py文件添加如下配置,该配置会把客户端请求自动转向https:
SECURE_SSL_REDIRECT = TrueCSRF_COOKIE_SECURE = True
