Nginx+uwsgi部署Django项目

原理

当加上动态请求后,部署网站就变得麻烦了,常常涉及到多个部分联动。对于Django项目的部署,常用的是用Nginx和uwsgi来部署。Nginx负责直接处理用户的请求,处理静态请求(图片,css之类的)并将动态请求转发给uwsgi。真正运行你Python代码的是uwsgi,它将Nginx递过来的请求给Django。这里有一个我在别处看到的很生动的比喻:当用户走进餐馆时,Nginx负责查看用户的预定,uwsgi负责接待用户并为其点菜,厨师则是Django,真正制作食物。

从上面的部署简要原理可以看出,我们需要处理3个部分:

  • Nginx
  • uwsgi
  • Django

我们挨个讲

Nginx配置

Nginx是一个高性能的HTTP和反向代理web服务器软件。它将作为用户访问网站请求的第一道关口

安装它,直接:

sudo apt-get install nginx


    然后我们处理它的配置。配置文件是 /etc/nginx/sites-available/default (你可能发现 /etc/nginx/ 下还有很多别的配置文件,但我们改上述这一个就行了,nginx在我们运行时(似乎)会自动改其他的)。我们改配置:

sudo vim /etc/nginx/sites-available/default


大部分默认内容都被注释了,不用管。我们关心的只有

server {
  listen 80 default_server;
  listen [::]80 default_server;

  server_name 192.168.114.514;

}

    其中“listen”的后面填你希望用于部署你网站的端口(一般为80或443,即http,https的默认端口,别的也行,不被占用就行。但那样访问你的网站需要在浏览器输入"192.168.114.514:你的端口号"就不能直接"192.168.114.514"了)

在server_name后面填你希望别人访问你网站使用的IP/域名。(我用的是内网穿透所以填局域网内那个“被穿透到”的ip就行,你有公网ip写公网ip就行)

我们还要加一些配置,让Nginx和uwsgi联动起来。文件末尾加上:

location / {
  include uwsgi_params;
  uwsgi_pass 127.0.0.1:8000;
}

    这为Nginx导入了uwsgi的模块。uwsgi_pass后面填写Nginx与uwsgi通讯的ip及端口。这个端口在之后配置uwsgi时会再让你选一遍,作为uwsgi运行的端口(8000是uwsgi的默认),注意这个和那个要一致。

(另外,因为这个端口仅是为Nginx和uwsgi通讯用的,所以ip直接填本地地址127.0.0.1就行了(除非你用到了很多服务器),这样的话只有在127.0.0.1上才知道你开了uwsgi。这就是说,nmap 127.0.0.1 会看到一个在8000端口叫http-alt的服务,就是uwsgi。但 nmap 192.168.114.514就看不到8000是开着的)

我们再来处理静态文件。按照原理,静态文件在请求到Nginx时就该被处理了(这就是为什么网站部署后出问题时,你可以先从别处访问静态文件来判断是Nginx的问题还是uwsgi的问题)。不过,如果你是按照django官方文档的标准做项目的,你的静态文件大概不会在一个统一的地方,但这个收集文件的事也不用你干。我们用django的manage.py:

python3 /path/to/your/project/manage.py collectstatic

(当然,你要先在settings.py中设置有关静态文件的事项才行)然后manage.py会自动生成一个存放了你所有静态文件的目录。

这些搞好了后我们来改Nginx配置,加上:

location /static {
  alias /path/to/staticfiles;
}

这里 /static 将会作为你网站线上的访问静态文件的url。比如,我在 /path/to/staticfiles/img 里有一张照片 pic.jpg,那网站上线后我可以在浏览器上输入 192.168.114.514/static/img/pic.jpg 来查看这张照片。

这样Nginx就基本配置完了,(我的)整个配置文件如下(刨去注释):

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  server_name 192.168.114.514;

  location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:8000;
  }

  location /static {
    alias /path/to/myproject/staticRoot;
  }
}

用一下Nginx的检查配置的功能

sudo nginx -t

没问题就试试启动服务

sudo service nginx start

用浏览器访问一下你的服务器,应该是:

Nginx+uwsgi部署Django项目_第1张图片

毕竟我们uwsgi都没配置呢
但此时静态文件应该可以访问了,可以试试:

Nginx+uwsgi部署Django项目_第2张图片

uwsgi配置

是时候处理uwsgi了。先从pip安装uWSGI:

pip3 install uwsgi

先看看终端输入uwsgi有没有反应,你可能要考虑把 ~/.local/bin/uwsgi 加入环境变量(否则不方便)。uwsgi 和Nginx不太一样,它不是一个服务,它就是一个可运行文件,所以最简单的使用uwsgi的方法是通过命令行参数来告诉uwsgi做什么。但那样太麻烦了,我们最好创建一个 .ini 文件来方便的写配置,比如:

sudo vim runuwsgi.ini

里面写上:

[uwsgi]

vhost = false

plugin = python3

http = 192.168.114.514:80
socket = 127.0.0.1:8000

chdir = /path/to/project/
#配置文件里的wsgi.py的地址
wsgi-file = /path/to/project/....../wsgi.py
processes = 4
threads = 2
#启动一个master进程来管理其他进程,其中的4个uwsgi进程都是这个master进程的子进程,如果kill这个master进程,相当于重启所有的uwsgi进程,方便关闭和重启
master=true
#保存启动之后主进程的pid
pidfile=/var/run/uwsgi.pid
#设置uwsgi后台运行,uwsgi.log保存日志信息 自动生成
daemonize=uwsgi.log

其中,

[uwsgi] 告诉系统这是一个uwsgi的ini文件

vhost是虚拟主机,无所谓

设置plugin是为了避免一个可能的bug

http填你希望别人访问的ip

socket填我们在Nginx配置里用于与uwsgi通讯的ip及端口

chdir是一个终端语句,它将目前的目录切换到项目目录

process threads master都是有关uwsgi工作线程设置的问题,按需求调下就行

pidfile 是保存主进程pid号的路径(其中 /var/run/ 是Linux中一个常被用于保存pid的目录)

daemonize 是保存日志的地方,这个日志会在uwsgi停止工作后更新

接着最好运行一下看看有没有问题,方便起见最好先把ini文件移动到项目目录里

sudo uwsgi --ini runuwsgi.ini

他可能说你用root运行了,不用管,部署用到的组件全sudo可能能避免一些用户权限的问题(如果还是有这方面问题,考虑是不是Nginx用了一个叫 www-data 的用户导致的问题)

你的运行大概是会成功的(查看Nginx和uwsgi的日志来确认,Nginx的日志在 /var/log/nginx/),但使用浏览器访问你的网站应该还看不到你想要的,这是因为你的Django代码还有需要改的地方。

Django配置

如果uwsgi还在运行,我们最好先把它关了。你可以找到你在pidfile里填的那个路径,查看uwsgi的pid, 然后kill了它。或者,你可以直接:

sudo killall -9 uwsgi

然后再来调整Django代码,可以参见:

https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/

但其中关键的东西很少,如果你完全不考虑安全问题的话(你最好不是)

在 settings.py 里设置 DEBUG = False 并设置 ALLOW_HOSTS = [" "] 为一些IP或域名。对于这些IP或域名,你允许它们从它们那里访问你的网站,这避免了一些可能的恶意行为,所以你要是不担心的话可以直接 ALLOW_HOST = ["*"] 这允许了所有的外部网站访问你的网站。不过你最好只填你服务器的IP,比如我就写了 ALLOW_HOST = ["127.0.0.1","192.168.114.514"]

这样就行了

错误排查

一般一次执行完上述操作一次成功的很少,或多或少都会有问题。我们需要一些排查问题的方法。既然我们在部署时涉及到了3部分,出问题肯定是它们中的一个出了问题(系统的问题就不说了)。

是不是Django代码的问题?考虑直接 python manage.py runserver 试一下能否正常运行

Django没问题了,怎么知道是Nginx还是uwsgi的问题?考虑先在终端运行:

sudo nmap 127.0.0.1
sudo nmap 192.168.114.514

看看80端口nginx的http、和8000(按照前文的设置)端口uwsgi的http-alt开没开。我们设想上127.0.0.1这两个应都开了,192.168.114.514(对外IP)应该就http开了。如果哪个口没开,绝对是有问题

如果的确是都工作了,但是没正常工作的话,考虑看nginx在 /var/log/nginx/ 里的日志文件,如果 error.log 里有报错的话,nginx没有正常工作,如果是"upstream prematurely closed connection while reading response header from upstream"的话是uwsgi有问题

别的问题…考虑在评论区发出来,我要会的话就帮你解答

你可能感兴趣的:(nginx,django,python,linux)