django+uwsgi+nginx 前后端分离部署配置

本文仅用于记录自己的踩坑过程,避免以后有同样需求的时候没思路

开发环境

后端部分

  • django==3.2.8
  • sqlite3==3.36.0

前端部分

  • vue==2.6.14
  • elementui (版本不知道)
  • axios (版本不知道)

服务器环境

  • uwsgi==2.0.20
  • nginx==1.20.1

所有的代码文件都位于 /myweb 目录下,该目录的结构如下:

这里的/myweb/backend/daily_exercise/exercise文件夹是使用 djangoadmin startproject 时自动创建的,/myweb/backend/daily_exercise/daily目录则是使用 python manage.py startapp 命令创建的

后端部分位于/myweb/backend/daily_exercise,前端部分位于/myweb/frontend/daily_exercise

后端使用 uwsgi 进行部署,加上 nginx 进行转发以避免跨站问题,前端只用 nginx 部署。

后端部署:uwsgi 部署 django

先安装 uwsgi

pip install uwsgi

然后在任意地方创建一个 uwsgi 的配置文件。本例中叫 uwsgi.ini,位于 /myweb/backend/ 目录下,虽然 /myweb/backend/daily_exercise/ 目录下还有一个同名的 uwsgi.ini,但是在服务器端部署用不到这个文件,这个文件是在本地部署时候用到的,因为在服务器上的 /myweb/backend/daily_exercise/ 目录被我设置成了 git 的远程仓库,所以在本地提交的时候也把这个配置文件提交上来了。
/myweb/backend/uwsgi.ini文件内容如下

[uwsgi]
http=:8000
master=True
processes=4
threads=4
chdir=/myweb/backend/daily_exercise
wsgi-file=/myweb/backend/daily_exercise/exercise/wsgi.py
vacuum=True
max-requests=5000
daemonize=/var/log/uwsgi/daily_exercise.log
pidfile=/tmp/daily_exercise.pid
py-autoreload=1

其中,要注意的是以下几个参数:

  • http 表示程序将要运行在哪个端口。本例是 8000
  • chdir 是 django 项目的根目录地址,也就是 manage.py 文件所在的目录
  • wsgi-file 是项目中 wsgi.py 文件地址。这里可以写成是相对地址,也可以是绝对地址
  • daemonize 指明 django 项目运行时产生的日志文件位置
  • pidfile 指定 django 项目运行时将要产生的进程文件名称和位置
  • py-autoreload 指定是否自动重载。如果等于 1,则在代码更新后,uwsgi 服务会自动重载。否则需要手动重载(命令是:uwsgi --reload /tmp/daily_exercise.pid)

然后执行:

uwsgi uwsgi.ini

即可部署完毕。可以查看 /var/log/uwsgi/daily_exercise.log 的内容,检查是否有报错,如果没有报错就没问题。同时也可以直接打开 http://服务器id:8000 (或其它在 django 中定义的有效路径)来观察部署结果。

前端部署:nginx 部署纯前端项目

如果系统中没有安装 nginx,需要先安装,网上有很多教程。

安装完后,修改 /etc/nginx/nginx.conf 配置文件

http {
  server {
    localhost /frontend/daily {
      alias /myweb/frontend/daily_exercise;
    }
  }
}

如上,在默认的 http > server 内加入以下三行即可。

    localhost /frontend/daily {
      alias /myweb/frontend/daily_exercise;
    }

其中 localhost 后面的 /frontend/daily 是自定义的访问地址,访问时在服务器地址后面加上这个自定义地址即可,如:http://服务器IP/frontend/daily

至此,前端、后端分别部署完毕。但是由于 django 部署使用的是 8000 端口,前端部署使用的是默认的 80 端口,前端发请求时会有跨站(CROS)问题。

比如,前端需要向后端接口 http://localhost:8000/daily/api 发请求获取数据,则在前端会出现跨站请求的错误。

一个解决的思路是,前端只向默认的 80 端口发请求,由 nginx 转发到 8000 端口,就不会有这个问题。

配置 nginx 解决跨站问题

同样简单,在前述的 nginx 配置文件 /etc/nginx/nginx.conf 文件中加上转发的规则,同样是在 http -> server 下添加:

locahost /daily/api {
  proxy_pass http://127.0.0.1:8000/daily/api;
  proxy_redirect default;
}

这样,当在浏览器中打开 http://服务器IP/daily/api 时,nginx 会转发至 http://127.0.0.1:8000/daily/api 这个地址。

当然以上是硬编码的方式,并不是最优解,网上还有其它方式可以更加灵活地实现这种不同端口之间的转发。

别忘了修改 django 项目中的跨站访问配置

需要安装 django 的 cros 插件:

pip install django-cros-headers

修改 /myweb/backend/daily_exercise/exercise/settings.py 文件,添加以下内容

CORS_ORIGIN_WHITELIST = (
    'http://127.0.0.1:8000',
    'http://localhost:8000',
    'http://localhost',
    'http://127.0.0.1',
)

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'POST',
    'PUT',
)

CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'Pragma',
)

再修改同文件下的MIDDLEWARE变量,增加corsheaders.middleware.CorsMiddleware

允许跨站(CROS问题解决)后,在前端代码中可以使用相对路径来访问后端的接口(这样可以在没有配置 nginx 转发的本地环境中也能正常运行),例如:

解决 sqlite3 版本过低的问题

在本地(或服务器)使用 python manage.py runserver 时,如果 sqlite3 版本过低,项目是运行不起来的,会 sqlite3 版本过低的错误,因为 django3 要求 sqlite3 的版本要大于等于 3.9.0,可以先按网上的教程升级系统的 sqlite3

sqlite 官网中提供的最新版本应该是远高于 3.9 的。
升级完后,使用 python manage.py runserver 命令执行应该没问题了,但是使用 uwsgi 部署时,很可能依然还会报版本过低的错误,如下,可在uwsgi.ini文件内指定的/var/log/uwsgi/daily_exercise.log文件中看到错误:

估计是程序找不到最新安装的 sqlite3,原因不明,也未找到解决办法,按网上说的添加参数到 bash_profile 无效,使用参数重新编译 python 也没有作用。

最终我是直接修改 django 中的判断语句来避开这个检测的。如上图中的黄色框部分,修改这个文件里面的check_sqlite_version函数,如下:

上图是修改后的,修改前黄框中应该是(3, 9, 0)

至此,问题解决,部署完毕!


解决管理后台静态文件丢失的问题

首先,需要配置一些变量,在settings文件末尾中添加:

配置url.py如下

最后执行 python manage.py collectstatic 操作,将相关静态文件都 copy 到 static_root 的路径下(实际是copy了admin的static文件到指定的 static 文件夹内)

posted @ 2021-10-26 15:12  东围居士  阅读(1081)  评论(0编辑  收藏  举报