nginx uwsgi django部署

虽然网上有很多这方面部署材料,但很多材料内容并不完善。即便搜索网上大量的部署材料,还是花了我好几天的时间才搞出来。部署步骤太复杂了,尤其uwsgi,感觉是反人类的设计。
言归正传,我的部署版本分别如下:
Nginx:nginx-1.16.0-1.el7.ngx.x86_64
uwsgi:2.0.18
django:2.2.3

uwsgi相关操作步骤

uwsgi安装

pip3 install uwsgi

安装好uwsgi后,在服务器上通过如下命令,启动服务。客户端在游览器上输入服务器IP地址,加上8001端口号,测试uwsgi是否正常工作

uwsgi --chdir /var/django/school --http :8001  --module school.wsgi:application
# /var/django/school:为django项目的路径(要使用绝对路径)
# 8001:为uwsgi开启服务的端口号
# school.wsgi:application:为与django的settings.py同级的wsgi文件路径

测试没问题后,再往下操作。

uwsgi.ini文件配置:
注意:
1 chdir、pidfile、socket不能加备注,如:# ,否则服务启动时会报错;
2 chdir要写绝对路径,指的路径为django项目目录路径,即manage.py所在的目录路径;
3 module要写相对路径,即wsgi.py文件的相对路径;
4 在django与manage.py同级目录,新建uwsgi.ini(名字可以任意取)。

[uwsgi]
chdir=/var/django/school
# home=/home/mysite_env			# optional path to a virtualenv
module=school.wsgi:application	
master=True
processes=4				# number of worker processes
harakiri=30				# respawn processes taking more than 20 seconds
post-buffering=65535			# harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers
max-requests=5000			# respawn processes after serving 5000 requests
vacuum=True				# clear environment on exit
socket=127.0.0.1:8001
pidfile=school-uwsgi-master.pid
daemonize=/var/log/nginx/uwsgi.log
disable-logging=true
log-maxsize=10000000
logdate=true

以下参数,建议只在开发时使用。当/var/django/school目录下的任何py文件改变时,自动重启uwsgi。否则,都要手工重启uwsgi服务。

py-auto-reload = 1			# auto restart uwsgi when *.py in/var/django/school was changed.

启动停止重启
通过以上代码配置,uWSGI启动后会在相同目录下生成一个 school-uwsgi-master.pid 的文件,里面只有一行内容是 uWSGI 的主进程的进程号。
启动:
uwsgi --ini uwsgi.ini
重启:
uwsgi --reload school-uwsgi-master.pid
停止:
uwsgi --stop school-uwsgi-master.pid

如果uwsgi服务启动异常,就无法通过上述方式停止uwsgi进程,要用下面的方式:
#查找主进程,然后杀掉。
netstat -antp | grep uwsgi
#kill pid会发送SIGTERM,只会导致重启,而不是结束掉。需要发送SIGINT或SIGQUIT才可以
kill -s SIGINT 3929

查询进程与端口:
ps aux | grep uwsgi
netstat -antp | grep uwsgi # 可以看到主进程PID。

logging参数解释:
daemonize:使进程在后台运行,并将日志打到指定的日志文件或者udp服务器

disable-logging:不记录请求信息的日志。只记录错误以及uWSGI内部消息到日志中(Django里使用print命令,打印出来的信息,还是会记录到日志文件里)。如果不加这一条,那么你的日志中会大量出现这种记录:
[pid: 347|app: 0|req: 106/367] 117.116.122.172 () {52 vars in 961 bytes} [Thu Jul 7 19:20:56 2016] POST /post => generated 65 bytes in 6 msecs (HTTP/1.1 200) 2 headers in 88 bytes (1 switches on core 0)

log-maxsize:以固定的文件大小(单位KB),切割日志文件。 例如:log-maxsize=10000000 就是10M一个日志文件。
logdate or log-date:在每一个日志行中都打印时间信息。你可以传入一个strftime()格式的参数,来格式化时间的格式。

其它参数解释:
master = true
#启动主进程,来管理其他进程,其它的uwsgi进程都是这个master进程的子进程,如果kill这个master进程,相当于重启所有的uwsgi进程。

chdir = /web/www/mysite
#在app加载前切换到当前目录, 指定运行目录

module = mysite.wsgi
#加载一个WSGI模块,这里加载mysite/wsgi.py这个模块

py-autoreload=1
#监控python模块mtime来触发重载 (只在开发时使用)

lazy-apps=true
#在每个worker而不是master中加载应用

socket=/test/myapp.sock
#指定socket文件,也可以指定为127.0.0.1:9000,这样就会监听到网络套接字

processes=2 #启动2个工作进程,生成指定数目的worker/进程

buffer-size=32768
#设置用于uwsgi包解析的内部缓存区大小为64k。默认是4k。

vacuum=true #当服务器退出的时候自动删除unix socket文件和pid文件。
listen=120 #设置socket的监听队列大小(默认:100)

pidfile=/var/run/uwsgi.pid #指定pid文件

enable-threads=true
#允许用内嵌的语言启动线程。这将允许你在app程序中产生一个子线程

reload-mercy=8
#设置在平滑的重启(直到接收到的请求处理完才重启)一个工作子进程中,等待这个工作结束的最长秒数。这个配置会使在平滑地重启工作子进程中,如果工作进程结束时间超过了8秒就会被强行结束(忽略之前已经接收到的请求而直接结束)

max-requests=5000
#为每个工作进程设置请求数的上限。当一个工作进程处理的请求数达到这个值,那么该工作进程就会被回收重用(重启)。你可以使用这个选项来默默地对抗内存泄漏

limit-as=256
#通过使用POSIX/UNIX的setrlimit()函数来限制每个uWSGI进程的虚拟内存使用数。这个配置会限制uWSGI的进程占用虚拟内存不超过256M。如果虚拟内存已经达到256M,并继续申请虚拟内存则会使程序报内存错误,本次的http请求将返回500错误。

harakiri=60
#一个请求花费的时间超过了这个harakiri超时时间,那么这个请求都会被丢弃,并且当前处理这个请求的工作进程会被回收再利用(即重启)

设置成开机自启动:

vi /etc/rc.d/rc.local
uwsgi --ini /var/django/school/uwsgi.ini

# 在centos7中,/etc/rc.d/rc.local的权限被降低了,所以需要执行如下命令赋予其可执行权限
chmod +x /etc/rc.d/rc.local

排错:
当访问django站点时,uwsgi后台报错如下:
no python application found, check your startup logs for errors

经过测试,一般是django启动时出现问题,仔细看uwsgi日志的启动信息,一般可以看到python3或django的错误信息。解决错误信息后,杀掉主进程再启动服务,方法如下:
#查找主进程,然后杀掉。
netstat -antp | grep uwsgi
#kill pid会发送SIGTERM,只会导致重启,而不是结束掉。需要发送SIGINT或SIGQUIT才可以
kill -s SIGINT 3929
#注:如果uwsgi启动正常时,通过这种方式无法杀掉进程,要用:uwsgi --stop school-uwsgi-master.pid

#也可以查看uwsgi.log日志,找出主进程。如果杀掉子进程,主进程会重启该子进程。例如下面uwsgi.log日志显示,杀掉子进程后,又重启了该子进程。
Thu Jul 11 23:15:42 2019 - spawned uWSGI master process (pid: 3903)
Thu Jul 11 23:15:42 2019 - spawned uWSGI worker 1 (pid: 3904, cores: 1)
Thu Jul 11 23:15:42 2019 - spawned uWSGI worker 2 (pid: 3905, cores: 1)
Thu Jul 11 23:15:42 2019 - spawned uWSGI worker 3 (pid: 3906, cores: 1)
Thu Jul 11 23:15:42 2019 - spawned uWSGI worker 4 (pid: 3907, cores: 1)
Thu Jul 11 23:18:02 2019 - DAMN ! worker 4 (pid: 3907) died ? trying respawn …
Thu Jul 11 23:18:02 2019 - Respawned uWSGI worker 4 (new pid: 3914)

Nginx相关操作

采用YUM安装nginx
1、添加源

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

2、安装Nginx
通过yum search nginx看看是否已经添加源成功。如果成功则执行下列命令安装Nginx。

sudo yum install -y nginx

3、启动Nginx并设置开机自动运行

sudo systemctl start nginx.service
sudo systemctl enable nginx.service

在nginx.conf里,部分代码解释:
include /etc/nginx/conf.d/.conf;
include /etc/nginx/sites-enabled/
;

增加nginx虚拟主机配置文件(conf.d)
在/etc/nginx/conf.d/,建立对应的域名配置文件,比如 /etc/nginx/conf.d/123.com.conf
需要注意,不同的虚拟主机配置文件,里面的端口号(listen 8000)不能重叠。

include /etc/nginx/sites-enabled/*;
#通过yum安装nginx/1.16.0,在nginx.conf没发现这段代码。在没有这条代码情况下,不需要从conf.d的文件创建快捷方式到sites-enabled。
#但可以手工在nginx里添加这条代码,并在/etc/nginx 目录下,创建一个sites-enabled。
sites-enabled是激活并使用的server配置(从conf.d的文件创建快捷方式到sites-enabled)
sudo ln -s /etc/nginx/conf.d/mysite_nginx.conf /etc/nginx/sites-enabled/

error_log /var/log/nginx/error.log warn;
#存放访问错误日志的路径

检查nginx配置文件语法是否有问题
nginx -t

配置Django的虚拟主机:
1 进入/etc/nginx/conf.d文件夹,重命名default.conf文件

mv default.conf default.conf_backup

2 vi school.conf

# the upstream component nginx needs to connect to
upstream django {
    # server unix:///path/to/your/mysite/mysite.sock; # for a file socket
    server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}

# configuration of the server
server {
    # the port your site will be served on
    listen      80;
    # the domain name it will serve for
    server_name Myschool; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    # Django media
    location /media  {
        alias /var/django/school/media;  # your Django project's media files - amend as required
    }

    location /static {
        alias /var/django/school/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
    }
}

特别注意:
1: uwsgi_pass一定要跟uwsgi_conf.ini中写的地址完全一致,uwsgi_pass也可以直接写:uwsgi_pass 127.0.0.1:8001。
2: uwsgi_params在nginx.conf同级文件夹下自带,
3: 如果nginx.conf文件里有“include /etc/nginx/sites-enabled/
;”代码,那么需要从conf.d的文件创建快捷方式到sites-enabled
Symlink to this file from /etc/nginx/sites-enabled so nginx can see it:
sudo ln -s /etc/nginx/conf.d/school.conf /etc/nginx/sites-enabled/*

Django部署配置清单
1: settings.py

# 关闭Debug和允许所有主机访问Django
DEBUG = False
ALLOWED_HOSTS = ['*']

2: 处理Django静态文件
收集静态文件

# 如果DEBUG=True   -> 使用项目目录下static内的静态文件
# 如果DEBUG=False  -> 使用STATIC_ROOT指定目录下的静态文件
# 这里的'/static/',决定url路径地址,比如写成'bruce',打开的地址就变成http://127.0.0.1:8000/bruce/css/CSSHome.css
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static")

# 设置静态文件查找目录
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

# 如果是home路径下则需要先设置目录权限
# 在模板中使用 fileObj.fileFieldName.url 代表网络可访问的资源路径
MEDIA_URL = '/media/'  # 代表访问media的url路径,例如 127.0.0.1/media/1.png
# 无论是否debug,都会访问此路径下的media资源(包括上传和访问)
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

收集所有静态文件到static_root指定目录:

python3 manage.py collectstatic

此时,依然无法访问static的文件,打开/var/log/nginx/error.log,发现大量日志为:failed (13: Permission denied)
可采用如下2中方法解决:
(1) 使用root账号运行nginx(不推荐):
修改nginx.conf,将头部的user nginx;改为如下:
user root;
如果不修改,静态文件会因为权限问题,导致访问被拒绝。

(2)chmod或chown:
对static和media所有文件夹和文件,授予755的权限;或者将所有文件夹和文件的归属者,改为nginx.

3 favicon.ico
将favicon.ico文件,放在manage.py同级目录里。

4: 设置上传文件目录的权限
如有配置文件上传功能,须确保文件目录的权限,任何人都可以上传文件。

5: 404\505错误页面
在/school/templates目录下,自定义404\505错误页面。比如添加:404.html

Django安全优化部署:
经过测试,这种安全优化部署需要登入系统后,环境变量才生效,所以并不好用,不推荐使用。

当部署Django等业务系统时,settings.py等文件里涉及数据库等密码信息,当部署的文件内容比较敏感时,将敏感信息放在环境变量里.然后使用python3的os.environ,调用环境变量,存放进settings.py对应的代码里.

注意:必须要通过输入用户名和密码登录(包括SSH);或不登入系统,但使用su命令切换用户,相应的环境变量才生效。所以当服务器重启后,在未登入情况下,环境变量是不生效的(因此有服务程序调用环境变量,这里需要注意).

所以,当使用环境变量来保存隐私信息时,就不能设置uwsgi服务自启动了。否则,会因为服务器重启,未登入系统,导致环境变量未生效,从而导致uwsgi启动失败。

注:settings.py里的SECRET_KEY作用,用来数据传输时,比如cookie传输时用来加密解密。
可以手工生成SECRET_KEY:

python3 manage.py shell
from django.core.management import utils
utils.get_random_secret_key()

将settings.py里的SECRET_KEY和mysql 以及redis的密码,配置在环境变量里
环境变量配置:

vi /etc/profile.d/django.sh
export SECRET_KEY='saah&kg@-sfmon_%h179e@den*jzya^@z_3*u5q^cwp9&+v^in'
export MYSQL_KEY='XXXXX'
export REDIS_KEY='XXXXX'

保存后,使用如下命令,是变量生效:

source /etc/profile

验证环境变量配置:

echo $MYSQL_KEY

在settings.py里,使用os.environ[“变量名”]调用

ENV_SECRET_KEY = os.environ['SECRET_KEY']
SECRET_KEY = ENV_SECRET_KEY

ENV_MYSQL_KEY = os.environ['MYSQL_KEY']
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        'NAME': 'schoolDB',
        'USER': 'django',
        'PASSWORD': ENV_MYSQL_KEY,
        'HOST': '192.168.0.100',
        'PORT': '3306',
    }
}

ENV_REDIS_KEY = os.environ['REDIS_KEY']
SESSION_REDIS = {
    'host': '192.168.0.100',
    'port': 6379,
    'db': 1,
    'password': ENV_REDIS_KEY,
    'prefix': 'session',
    'socket_timeout': 10
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值