浅谈Django+Gunicorn+Nginx部署之路


Posted in Python onSeptember 11, 2019

前言

最近,我已经成功将我的个人网站从 Flask 迁移到 Django 了,最早接触 Django 的时候大概是在 4 年前,我记得那个时候 Django 中的路由配置使用 正则 来进行的,但是我有特别烦这个东西,所以就果断弃坑了。然后今年年初的时候,我用 Flask 写了一个我的个人网站,刚开始的时候功能还是比较简单,看着路由配置和部署规则都很方便,就果断采用了。但是后来我想添加的功能越来越多的时候,我发现我已经越来越难掌控它了,正好最近我稍微看了一下 Django 这几年的变化,最新的 2.2 版本还是很不错的,路由规则和 Flask 已经一致了,所以我就重新入坑了。

目前我的个人网站基本功能已经迁移完毕。但是在部署的时候,我遇到了一些问题,在网上看了一些解决方法,要么太乱,要么太旧,个人觉得都已经不太适用了。所以在这里记录一下我的部署过程。

部署

网上有很多都是用 UWSGI 的方式来部署,但是我个人比较喜欢 Gunicorn,所以以下内容我只是记录了 Django + Gunicorn + Nginx 在 Ubuntu 上的部署方式相关内容。

步骤一

上传网站源码至目标服务器

由于我的源码是用 Github 来托管的,所以我直接执行下述命令来克隆我的网站源码到服务器即可。

git clone https://github.com/your-name/repo-name.git

# 进入项目目录
cd repo-name

# 创建并激活虚拟环境
python3 -m virtualenv venv
source venv/bin/activate

# 安装项目依赖
pip install -r requirements.txt

目前我的网站采用的相关依赖包如下:

autopep8
Django
django-bootstrap4
django-ckeditor
gunicorn
Markdown
Pillow
python-slugify
requests

这里有个坑需要注意,如果你使用了 awesome-slugify,请尝试使用 python-slugify,因为有的服务器可能无法正常安装 awesome-slugify,具体 BUG 可参考:Clashes with python-slugify package。

步骤二

修改项目相关配置,并进行静态资源收集

由于我需要将我的网站部署到生产环境,所以我需要关闭 Django 的调试模式,并修改静态资源相关配置,示例配置如下所示:

settings.py

SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')

DEBUG = os.environ.get('DJANGO_DEBUG', False)

TEMPLATE_DEBUG = os.environ.get('DJANGO_TEMPLATE_DEBUG', False)

ALLOWED_HOSTS = ["*"]

TEMPLATES = [
  {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(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',
      ],
    },
  },
]

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
  os.path.join(BASE_DIR, 'static'),
]

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

然后执行如下命令进行静态资源收集:

python manage.py collectstatic

之后,我还需要创建一个 Gunicorn 进程的相关配置,示例配置如下所示:

gunicorn.conf.py

# 安装
# sudo pip3 install gunicorn

import sys
import os
import logging
import logging.handlers
from logging.handlers import WatchedFileHandler
import multiprocessing

BASE_DIR = '/home/hippie/hippiezhou.fun/src'
sys.path.append(BASE_DIR)

LOG_DIR = os.path.join(BASE_DIR, 'log')
if not os.path.exists(LOG_DIR):
  os.makedirs(LOG_DIR)

# 绑定的ip与端口
bind = "0.0.0.0:8000"

# 以守护进程的形式后台运行
daemon = True

# 最大挂起的连接数,64-2048
backlog = 512

# 超时
timeout = 30

# 调试状态
debug = False

# gunicorn要切换到的目的工作目录
chdir = BASE_DIR

# 工作进程类型(默认的是 sync 模式,还包括 eventlet, gevent, or tornado, gthread, gaiohttp)
worker_class = 'sync'

# 工作进程数
workers = multiprocessing.cpu_count()

# 指定每个工作进程开启的线程数
threads = multiprocessing.cpu_count() * 2

# 日志级别,这个日志级别指的是错误日志的级别(debug、info、warning、error、critical),而访问日志的级别无法设置
loglevel = 'info'

# 日志格式
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
# 其每个选项的含义如下:
'''
h     remote address
l     '-'
u     currently '-', may be user name in future releases
t     date of the request
r     status line (e.g. ``GET / HTTP/1.1``)
s     status
b     response length or '-'
f     referer
a     user agent
T     request time in seconds
D     request time in microseconds
L     request time in decimal seconds
p     process ID
'''

# 访问日志文件
accesslog = os.path.join(LOG_DIR, 'gunicorn_access.log')
# 错误日志文件
errorlog = os.path.join(LOG_DIR, 'gunicorn_error.log')
# pid 文件
pidfile = os.path.join(LOG_DIR, 'gunicorn_error.pid')

# 访问日志文件,"-" 表示标准输出
accesslog = "-"
# 错误日志文件,"-" 表示标准输出
errorlog = "-"

# 进程名
proc_name = 'hippiezhou_fun.pid'

# 更多配置请执行:gunicorn -h 进行查看

之后可用通过如下方式启动我们的网站:

# 启动方式(首先需要切换到项目根目录,即和 manage.py 在同级目录下):

gunicorn -c gunicorn.conf.py website.wsgi:application

# 或
gunicorn website.wsgi:application -b 0.0.0.0:8000 -w 4 -k gthread

# 或
gunicorn website.wsgi:application -b 0.0.0.0:8000 -w 4 -k gthread --thread 40 --max-requests 4096 --max-requests-jitter 512

# 查看进程
ps aux | grep gunicorn

步骤三

配置 Nginx

通过前两步,我们可以成功将我们的网站跑起来,但是目前还只能在内部访问,所以我们需要通过 Nginx 来做反向代理,供外网访问。

执行下述命令进行安装和配置

sudo apt-get install nginx

sudo service nginx start

# 备份默认配置
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak

# 启动 Vim 修改我们的网站配置
sudo vim /etc/nginx/sites-available/default

示例配置如下所示:

server{
    ...
    server_name hippiezhou.fun *.hippiezhou.fun;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    ...

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        # try_files $uri $uri/ =404;
        proxy_pass     http://127.0.0.1:8000; #此处要和你 gunicore 的 ip 和端口保持一致
        proxy_redirect   off;

        proxy_set_header  Host         $host;
        proxy_set_header  X-Real-IP      $remote_addr;
        proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto  $scheme;
    }

    location /static {
        alias /root/hippiezhou.fun/src/staticfiles; # 此次需要配置为你的网站对应的静态资源的绝对路径
    }

    location /media {
        alias /root/hipiezhou.fun/src/media; # 如果你的网站有上传功能,需要配置该结点并指向目标路径
    }

    ...
}

配置完成后执行下述操作即可将我们的网站运行起来

# 若网站未启动执行该命令
gunicorn -c gunicorn.conf.py website.wsgi:application

sudo nginx -t
sudo service nginx restart

如果不出意外,网站应该是可以正常访问,如果静态资源依然不能访问,打开网站的 开发者工具看一下是什么错误。

  • 如果是 404 的问题,请确保你的 settings 相关配置和我上面列出来的是一致的;
  • 如果是 403 的问题,应该是 Nginx 无权访问你指定的静态资源,你需要修改 Nginx 的用户类型,亲执行下述命令
sudo vim /etc/nginx/nginx.conf

将 user 后面的值修改为 root,然后重启 Nginx 即可。

最后,关于如何配置 HTTPS,这里就不过多介绍了,直接列出相关示例脚本:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx

sudo certbot --nginx

# sudo certbot renew --dry-run

sudo ufw allow https

sudo systemctl restart nginx

总结

在部署的过程中,其实遇到最多的问题就是关于静态资源无法问题的问题,但是看到网上很多文章,都不一样,并且有的写的还是错误的。所以这里就总结一些。还好,一切顺利。算是填了 4 年前的一个坑吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 实现归并排序算法
Jun 05 Python
python通过zlib实现压缩与解压字符串的方法
Nov 19 Python
1 行 Python 代码快速实现 FTP 服务器
Jan 25 Python
基于Python socket的端口扫描程序实例代码
Feb 09 Python
Python模拟浏览器上传文件脚本的方法(Multipart/form-data格式)
Oct 22 Python
python 监测内存和cpu的使用率实例
Nov 28 Python
tensorflow 动态获取 BatchSzie 的大小实例
Jun 30 Python
Python如何执行系统命令
Sep 23 Python
如何使用python写截屏小工具
Sep 29 Python
Python3中FuzzyWuzzy库实例用法
Nov 18 Python
python基于scrapy爬取京东笔记本电脑数据并进行简单处理和分析
Apr 14 Python
python高温预警数据获取实例
Jul 23 Python
初次部署django+gunicorn+nginx的方法步骤
Sep 11 #Python
python 如何将数据写入本地txt文本文件的实现方法
Sep 11 #Python
学习Django知识点分享
Sep 11 #Python
windows 10 设定计划任务自动执行 python 脚本的方法
Sep 11 #Python
使用Python为中秋节绘制一块美味的月饼
Sep 11 #Python
python破解bilibili滑动验证码登录功能
Sep 11 #Python
python修改FTP服务器上的文件名
Sep 11 #Python
You might like
基于php-fpm的配置详解
2013/06/03 PHP
处理(php-cgi.exe - FastCGI 进程超过了配置的请求超时时限)的问题
2013/07/03 PHP
php生成唯一的订单函数分享
2015/02/02 PHP
php检测mysql表是否存在的方法小结
2017/07/20 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
thinkphp整合系列之极验滑动验证码geetest功能
2019/06/18 PHP
JavaScript XML操作 封装类
2009/07/01 Javascript
JavaScript 用cloneNode方法克隆节点的代码
2012/10/15 Javascript
原生javascript实现图片按钮切换
2015/01/12 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
jQuery+HTML5实现手机摇一摇换衣特效
2015/06/05 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
jquery左右全屏大尺寸多图滑动效果代码分享
2015/08/28 Javascript
JavaScript基本类型值-Number类型
2017/02/24 Javascript
纯js的右下角弹窗实例
2017/03/12 Javascript
详解vue组件通信的三种方式
2017/06/30 Javascript
jQuery自动或手动图片切换效果
2017/10/11 jQuery
详解JavaScript 中 if / if...else...替换方式
2018/07/15 Javascript
vue中进行微博分享的实例讲解
2019/10/14 Javascript
功能完善的小程序日历组件的实现
2020/03/31 Javascript
JavaScript中的this妙用实例分析
2020/05/09 Javascript
vue-router的hooks用法详解
2020/06/08 Javascript
Python使用matplotlib填充图形指定区域代码示例
2018/01/16 Python
python3+selenium实现qq邮箱登陆并发送邮件功能
2019/01/23 Python
Python Django框架防御CSRF攻击的方法分析
2019/10/18 Python
Python 如何对文件目录操作
2020/07/10 Python
M1芯片安装python3.9.1的实现
2021/02/02 Python
Html5自定义字体解决方法
2019/10/09 HTML / CSS
J2EE面试题
2016/03/14 面试题
土木工程建筑专业毕业生求职信
2013/10/21 职场文书
军训感想500字
2014/02/20 职场文书
2014年清明节寄语
2014/04/03 职场文书
2015年九一八事变纪念日演讲稿
2015/03/19 职场文书
我的生日感言
2015/08/03 职场文书
嵌入式Redis服务器在Spring Boot测试中的使用教程
2021/07/21 Redis
golang实现一个简单的websocket聊天室功能
2021/10/05 Golang