vlambda博客
学习文章列表

*记:基于Centos+uWSGI+Nginx部署web应用

This browser does not support music or audio playback. Please play it in Weixin or another browser.

碎碎念


- 最近在给手里在做的几个python web应用统一配置云服务器。期间涉及的配置步骤和一些通信概念还是比较多,而且网上提供的方法大多都不是很有效,鱼龙混杂。故写篇文章详细记录一下过程,整合一些可信且有效的信息来源,方便乘凉/提前周更。

- 本文是对 在基于Centos系统的云服务器上配置python web 的一个简略的过程记录,此外还包括了django的产品环境配置,以及对python web通信协议WSGInginx代理服务器等概念的介绍。


【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.txt
django==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__.py base.py local.py pro.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.conf 
upstream 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.conf http { ...... # 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