当加上动态请求后,部署网站就变得麻烦了,常常涉及到多个部分联动。对于Django项目的部署,常用的是用Nginx和uwsgi来部署。Nginx负责直接处理用户的请求,处理静态请求(图片,css之类的)并将动态请求转发给uwsgi。真正运行你Python代码的是uwsgi,它将Nginx递过来的请求给Django。这里有一个我在别处看到的很生动的比喻:当用户走进餐馆时,Nginx负责查看用户的预定,uwsgi负责接待用户并为其点菜,厨师则是Django,真正制作食物。
从上面的部署简要原理可以看出,我们需要处理3个部分:
我们挨个讲
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
用浏览器访问一下你的服务器,应该是:
毕竟我们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代码还有需要改的地方。
如果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有问题
别的问题…考虑在评论区发出来,我要会的话就帮你解答