如何在Ubuntu16.04上使用uWSGI和Nginx服务Django应用程序
介绍
Django 是一个强大的 Web 框架,可以帮助您启动 Python 应用程序或网站。 Django 包含一个简化的开发服务器,用于在本地测试您的代码,但对于任何与生产相关的事情,都需要一个更安全、更强大的 Web 服务器。
在本指南中,我们将演示如何在 Ubuntu 16.04 上安装和配置一些组件以支持和服务 Django 应用程序。 我们将配置 uWSGI 应用程序容器服务器以与我们的应用程序交互。 然后,我们将设置 Nginx 以反向代理到 uWSGI,使我们能够访问其安全性和性能特性来为我们的应用程序提供服务。
先决条件和目标
为了完成本指南,您应该拥有一个全新的 Ubuntu 16.04 服务器实例,该实例具有配置了 sudo
权限的非 root 用户。 您可以通过我们的 初始服务器设置指南 来了解如何设置它。
我们将在两个不同的虚拟环境中安装 Django。 这将允许单独处理您的项目及其要求。 我们将创建两个示例项目,以便我们可以在多项目环境中运行这些步骤。
一旦我们有了我们的应用程序,我们将安装和配置 uWSGI 应用程序服务器。 这将作为我们应用程序的接口,它将使用 HTTP 的客户端请求转换为我们的应用程序可以处理的 Python 调用。 然后,我们将在 uWSGI 前面设置 Nginx,以利用其高性能的连接处理机制和易于实现的安全特性。
让我们开始吧。
安装和配置 VirtualEnv 和 VirtualEnvWrapper
我们将在他们自己的虚拟环境中安装我们的 Django 项目,以隔离每个项目的需求。 为此,我们将安装 virtualenv
,它可以创建 Python 虚拟环境,以及 virtualenvwrapper
,它为 virtualenv
工作流程增加了一些可用性改进。
我们将使用 Python 包管理器 pip
安装这两个组件。 我们可以从 Ubuntu 存储库安装此实用程序。
如果您使用 Python 2 构建 Django 项目,请输入:
sudo apt-get update sudo apt-get install python-pip
如果您使用的是 Python 3,请键入:
sudo apt-get update sudo apt-get install python3-pip
现在您已经安装了 pip
,我们可以全局安装 virtualenv
和 virtualenvwrapper
。 我们还将使用 pip
本身将 pip
升级到最新版本。
如果您使用 Python 2,请键入:
sudo -H pip install --upgrade pip sudo -H pip install virtualenv virtualenvwrapper
如果您使用的是 Python 3,请键入:
sudo -H pip3 install --upgrade pip sudo -H pip3 install virtualenv virtualenvwrapper
安装这些组件后,我们现在可以使用 virtualenvwrapper
脚本所需的信息来配置我们的 shell。 我们的虚拟环境都将放置在我们的主文件夹中名为 Env
的目录中,以便于访问。 这是通过一个名为 WORKON_HOME
的环境变量来配置的。 我们可以将它添加到我们的 shell 初始化脚本中,并且可以获取虚拟环境包装器脚本。
如果您使用 Python 3 和 pip3
命令,您还必须在 shell 初始化脚本中添加一行:
echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.bashrc
无论您使用的是哪个版本的 Python,您都需要运行以下命令:
echo "export WORKON_HOME=~/Env" >> ~/.bashrc echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc
现在,获取您的 shell 初始化脚本,以便您可以在当前会话中使用此功能:
source ~/.bashrc
您现在应该在您的主文件夹中有一个名为 Env
的目录,该目录将保存虚拟环境信息。
创建 Django 项目
现在我们有了虚拟环境工具,我们将创建两个虚拟环境,在每个环境中安装 Django,并启动两个项目。
创建第一个项目
我们可以使用 virtualenvwrapper
脚本提供给我们的一些命令轻松创建虚拟环境。
通过键入以下内容,使用您的第一个站点或项目的名称创建您的第一个虚拟环境:
mkvirtualenv firstsite
这将创建一个虚拟环境,在其中安装 Python 和 pip
,并激活环境。 您的提示将更改以指示您现在正在新的虚拟环境中操作。 它看起来像这样:(firstsite)user@hostname:~$
。 括号中的值是您的虚拟环境的名称。 通过 pip
安装的任何软件现在都将安装到虚拟环境中,而不是安装在全局系统中。 这允许我们在每个项目的基础上隔离我们的包。
我们的第一步是安装 Django 本身。 我们可以在没有 sudo
的情况下使用 pip
,因为我们是在虚拟环境中本地安装它:
pip install django
安装 Django 后,我们可以通过键入以下内容创建我们的第一个示例项目:
cd ~ django-admin.py startproject firstsite
这将在您的主目录中创建一个名为 firstsite
的目录。 其中有一个用于处理项目各个方面的管理脚本和另一个用于存放实际项目代码的同名目录。
移动到第一级目录,以便我们可以开始设置示例项目的最低要求。
cd ~/firstsite
首先迁移数据库以初始化我们项目将使用的 SQLite 数据库。 如果您愿意,您可以为您的应用程序设置一个备用数据库,但这超出了本指南的范围:
~/firstsite/manage.py migrate
您现在应该在项目目录中有一个名为 db.sqlite3
的数据库文件。 现在,我们可以通过键入以下内容来创建管理用户:
~/firstsite/manage.py createsuperuser
此时,您的项目目录(本例中为 ~/firstsite
)应具有以下内容:
~/firstsite/manage.py
:一个 Django 项目管理脚本。~/firstsite/firstsite/
:Django 项目包。 这应该包含__init__.py
、settings.py
、urls.py
和wsgi.py
文件。~/firstsite/db.sqlite3
:用于存储站点信息的 SQLite 数据库文件。
接下来,使用文本编辑器打开项目的设置文件:
nano ~/firstsite/firstsite/settings.py
首先找到 ALLOWED_HOSTS
指令。 这定义了可用于连接到 Django 实例的服务器地址或域名的列表。 任何带有不在此列表中的 Host 标头的传入请求都将引发异常。 Django 要求您设置它以防止某一类安全漏洞。
在方括号中,列出与您的 Django 服务器关联的 IP 地址或域名。 每个项目都应列在引号中,条目之间用逗号分隔。 如果您希望请求整个域和任何子域,请在条目的开头添加句点。 在下面的代码片段中,有一些注释掉的示例用于演示:
~/firstsite/firstsite/settings.py
. . . # The simplest case: just add the domain name(s) and IP addresses of your Django server # ALLOWED_HOSTS = [ 'example.com', '203.0.113.5'] # To respond to 'example.com' and any subdomains, start the domain with a dot # ALLOWED_HOSTS = ['.example.com', '203.0.113.5'] ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]
由于我们将设置 Nginx 来为我们的网站提供服务,我们需要配置一个目录来保存我们网站的静态资产。 这将允许 Nginx 直接为这些服务,这将对性能产生积极影响。 我们将告诉 Django 将它们放入项目基目录中名为 static
的目录中。 将此行添加到文件底部以配置此行为:
~/firstsite/firstsite/settings.py
. . . STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
完成后保存并关闭文件。 现在,收集我们网站的静态元素并将它们放在该目录中,输入:
~/firstsite/manage.py collectstatic
可能会要求您输入“是”以确认操作并收集静态内容。 在您的项目目录中将有一个名为 static
的新目录。
接下来,我们可以打开一个端口,以便我们可以访问 Django 开发服务器。 如果您遵循初始服务器设置指南,则应该启用 UFW 防火墙。 通过键入以下内容允许连接到端口 8080:
sudo ufw allow 8080
完成所有这些后,我们可以通过临时启动开发服务器来测试我们的项目。 类型:
~/firstsite/manage.py runserver 0.0.0.0:8080
这将在端口 8080
上启动开发服务器。 在浏览器中访问您服务器的域名或 IP 地址,后跟 8080
:
http://server_domain_or_IP:8080
您应该会看到如下所示的页面:
将 /admin
添加到浏览器地址栏中 URL 的末尾,您将被带到管理员登录页面:
使用您通过 createsuperuser
命令选择的管理登录凭据,登录到服务器。 然后,您将可以访问管理界面:
测试完此功能后,通过在终端中键入 CTRL-C 来停止开发服务器。 我们现在可以继续我们的第二个项目。
创建第二个项目
第二个项目的创建方式与第一个项目完全相同。 我们将在本节中删减解释,看看您是如何完成这一次的。
回到您的主目录并为您的新项目创建第二个虚拟环境。 激活后在这个新环境中安装 Django:
cd ~ mkvirtualenv secondsite pip install django
将创建新环境 并将 更改为,保留您以前的虚拟环境。 这个 Django 实例与您配置的另一个实例完全分开。 这使您可以独立管理它们并根据需要进行自定义。
创建第二个项目并进入项目目录:
cd ~ django-admin.py startproject secondsite cd ~/secondsite
初始化数据库并创建一个管理用户:
~/secondsite/manage.py migrate ~/secondsite/manage.py createsuperuser
打开设置文件:
nano ~/secondsite/secondsite/settings.py
将 ALLOWED_HOSTS
设置为您的第二个项目的域、服务器的 IP 地址或两者,就像您对第一个项目所做的那样:
ALLOWED_HOSTS = ['second_project_domain_or_IP', 'another_domain_or_IP', . . .]
添加静态文件的位置,就像您在上一个项目中所做的那样:
~/secondsite/secondsite/settings.py
. . . STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
保存并关闭文件。 现在,通过键入以下命令将静态元素收集到该目录中:
~/secondsite/manage.py collectstatic
最后,启动开发服务器来测试站点:
~/secondsite/manage.py runserver 0.0.0.0:8080
您应该在以下网址查看常规网站:
http://server_domain_or_IP:8080
同时登录管理站点:
http://server_domain_or_IP:8080/admin
当您确认一切都按预期工作时,在终端中键入 CTRL-C 以停止开发服务器。
退出虚拟环境
由于我们现在已经完成了指南的 Django 部分,我们可以停用我们的第二个虚拟环境:
deactivate
如果您需要再次在任一 Django 站点上工作,您应该重新激活它们各自的环境。 您可以使用 workon
命令来做到这一点:
workon firstsite
或者:
workon secondsite
同样,在您完成网站工作后停用:
deactivate
我们现在可以继续配置应用程序服务器。
设置 uWSGI 应用服务器
现在我们已经设置了两个 Django 项目并准备就绪,我们可以配置 uWSGI。 uWSGI 是一个应用服务器,可以通过称为 WSGI 的标准接口与应用程序进行通信。 要了解更多信息,请阅读我们在 Ubuntu 14.04 上设置 uWSGI 和 Nginx 指南的 本节 。
安装 uWSGI
与上面链接的指南不同,在本教程中,我们将全局安装 uWSGI。 这将在处理多个 Django 项目时减少摩擦。 在我们安装 uWSGI 之前,我们需要软件所依赖的 Python 开发文件。 我们可以直接从 Ubuntu 的存储库中安装它。
如果您将 Django 与 Python 2 一起使用,请键入:
sudo apt-get install python-dev
如果您使用的是 Python 3,请键入:
sudo apt-get install python3-dev
现在开发文件已经可用,我们可以通过pip
全局安装uWSGI。
如果您使用 Python 2,请键入:
sudo -H pip install uwsgi
如果您使用的是 Python 3,请键入:
sudo -H pip3 install uwsgi
我们可以通过将我们的站点之一的信息传递给它来快速测试这个应用程序服务器。 例如,我们可以通过键入以下命令告诉它为我们的第一个项目服务:
uwsgi --http :8080 --home /home/sammy/Env/firstsite --chdir /home/sammy/firstsite -w firstsite.wsgi
在这里,我们告诉 uWSGI 使用位于我们的 ~/Env
目录中的虚拟环境,切换到我们的项目目录,并使用存储在我们内部 [X186X 中的 wsgi.py
文件] 目录来提供文件(使用 firstsite.wsgi
Python 模块语法)。 对于我们的演示,我们告诉它在端口 8080
上提供 HTTP。
如果您在浏览器中访问服务器的域名或IP地址,然后输入:8080
,您将再次看到您的站点(/admin
界面中的静态元素,如CSS,将不起作用然而)。 完成此功能的测试后,在终端中键入 CTRL-C。
创建配置文件
从命令行运行 uWSGI 对于测试很有用,但对于实际部署并不是特别有用。 相反,我们将在“Emperor 模式”下运行 uWSGI,它允许主进程在给定一组配置文件的情况下自动管理单独的应用程序。
创建一个存放配置文件的目录。 由于这是一个全局进程,我们将创建一个名为 /etc/uwsgi/sites
的目录来存储我们的配置文件:
sudo mkdir -p /etc/uwsgi/sites
在这个目录中,我们将放置我们的配置文件。 我们需要为我们服务的每个项目提供一个配置文件。 uWSGI 进程可以采用多种格式的配置文件,但由于其简单性,我们将使用 .ini
文件。
为您的第一个项目创建一个文件并在文本编辑器中打开它:
sudo nano /etc/uwsgi/sites/firstsite.ini
在内部,我们必须从 [uwsgi]
节标题开始。 我们所有的信息都将放在此标题下方。 我们还将使用变量来使我们的配置文件更可重用。 在标题之后,使用您的第一个项目的名称设置一个名为 project
的变量。 添加一个名为 uid
的变量,其中包含您的 sudo
用户名。
我们还将添加一个名为 base
的变量,其中包含用户主目录的路径。 这将从我们使用 %(variable_name)
语法设置的用户名构造。 读取配置时,这将被变量的值替换:
/etc/uwsgi/sites/firstsite.ini
[uwsgi] project = firstsite uid = sammy base = /home/%(uid)
接下来,我们需要配置 uWSGI 以便它正确处理我们的项目。 我们需要通过设置 chdir
选项进入项目根目录。 我们可以使用相同的变量语法组合主目录和项目名称。
以类似的方式,我们将为我们的项目指明虚拟环境。 通过设置模块,我们可以准确地指示如何与我们的项目交互(通过从我们的内部项目目录中的 wsgi.py
文件中导入可调用的“应用程序”)。 这些项目的配置将如下所示:
/etc/uwsgi/sites/firstsite.ini
[uwsgi] project = firstsite uid = sammy base = /home/%(uid) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application
我们想创建一个有 5 个工作人员的主进程。 我们可以通过添加这个来做到这一点:
/etc/uwsgi/sites/firstsite.ini
[uwsgi] project = firstsite uid = sammy base = /home/%(uid) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application master = true processes = 5
接下来我们需要指定 uWSGI 应该如何监听连接。 在我们对 uWSGI 的测试中,我们使用了 HTTP 和一个网络端口。 但是,由于我们将使用 Nginx 作为反向代理,因此我们有更好的选择。
我们可以使用 Unix 套接字,而不是使用网络端口,因为所有组件都在单个服务器上运行。 这更安全并提供更好的性能。 这个套接字不会使用 HTTP,而是会实现 uWSGI 的 uwsgi
协议,这是一种用于与其他服务器通信的快速二进制协议。 Nginx 可以使用 uwsgi
协议进行原生代理,所以这是我们最好的选择。
我们还将修改套接字的所有权和权限,因为我们将授予 Web 服务器写入权限。 我们将设置 vacuum
选项,以便在服务停止时自动清理套接字文件:
/etc/uwsgi/sites/firstsite.ini
[uwsgi] project = firstsite uid = sammy base = /home/%(uid) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application master = true processes = 5 socket = /run/uwsgi/%(project).sock chown-socket = %(uid):www-data chmod-socket = 660 vacuum = true
至此,我们第一个项目的uWSGI配置就完成了。 保存并关闭文件。
使用变量设置文件的优点是它使重用变得非常简单。 复制您的第一个项目的配置文件以用作您的第二个配置文件的基础:
sudo cp /etc/uwsgi/sites/firstsite.ini /etc/uwsgi/sites/secondsite.ini
使用文本编辑器打开第二个配置文件:
sudo nano /etc/uwsgi/sites/secondsite.ini
我们只需要更改此文件中的单个值即可使其适用于我们的第二个项目。 使用您在第二个项目中使用的名称修改 project
变量:
/etc/uwsgi/sites/secondsite.ini
[uwsgi] project = secondsite uid = sammy base = /home/%(uid) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application master = true processes = 5 socket = /run/uwsgi/%(project).sock chown-socket = %(uid):www-data chmod-socket = 660 vacuum = true
完成后保存并关闭文件。 您的第二个项目现在应该可以开始了。
为 uWSGI 创建一个 systemd 单元文件
我们现在有了为 Django 项目提供服务所需的配置文件,但我们还没有自动化这个过程。 接下来,我们将创建一个 systemd 单元文件来管理 uWSGI 皇帝进程并在启动时自动启动 uWSGI。
我们将在 /etc/systemd/system
目录中创建单元文件,保存管理员创建的单元文件。 我们将调用我们的文件 uwsgi.service
:
sudo nano /etc/systemd/system/uwsgi.service
从 [Unit]
部分开始,用于指定元数据和排序信息。 我们将在这里简单地描述我们的服务:
/etc/systemd/system/uwsgi.service
[Unit] Description=uWSGI Emperor service
接下来,我们将打开 [Service]
部分。 我们将使用 ExecStartPre
指令来设置运行服务器所需的部分。 这将确保创建 /run/uwsgi
目录,并且我们的普通用户拥有它,并且 www-data
组作为组所有者。 带有 -p
标志的 mkdir
和 chown
命令即使不需要它们的操作也会成功返回。 这就是我们想要的。
对于由 ExecStart
指令指定的实际启动命令,我们将指向 uwsgi
可执行文件。 我们将告诉它以“Emperor 模式”运行,允许它使用在 /etc/uwsgi/sites
中找到的文件来管理多个应用程序。 我们还将添加 systemd 正确管理流程所需的部分。 这些取自 uWSGI 文档 这里 。
/etc/systemd/system/uwsgi.service
[Unit] Description=uWSGI Emperor service [Service] ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi' ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all
现在,我们需要做的就是添加 [Install]
部分。 这允许我们指定何时应该自动启动服务。 我们将把我们的服务绑定到多用户系统状态。 每当系统为多个用户设置(正常运行条件)时,我们的服务将被激活:
/etc/systemd/system/uwsgi.service
[Unit] Description=uWSGI Emperor service [Service] ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi' ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all [Install] WantedBy=multi-user.target
完成后,保存并关闭文件。
此时我们将无法成功启动服务,因为它依赖于可用的 www-data
用户。 我们将不得不等到安装 Nginx 之后才能启动 uWSGI 服务。
安装和配置 Nginx 作为反向代理
配置好 uWSGI 并准备就绪后,我们现在可以安装和配置 Nginx 作为我们的反向代理。 这可以从 Ubuntu 的默认存储库下载:
sudo apt-get install nginx
安装 Nginx 后,我们可以继续为每个项目创建一个服务器块配置文件。 通过创建服务器块配置文件从第一个项目开始:
sudo nano /etc/nginx/sites-available/firstsite
在内部,我们可以通过指示我们的第一个项目应该可以访问的端口号和域名来启动我们的服务器块。 server_name
块 必须 匹配服务器的域名之一或其 IP 地址,否则可以使用默认的 Nginx 页面代替。 我们假设您有一个域名:
/etc/nginx/sites-available/firstsite
server { listen 80; server_name firstsite.com www.firstsite.com; }
接下来,如果 Nginx 找不到 favicon,我们可以告诉它不要担心。 我们还将它指向我们收集站点静态元素的静态文件目录的位置:
/etc/nginx/sites-available/firstsite
server { listen 80; server_name firstsite.com www.firstsite.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/sammy/firstsite; } }
接下来我们可以创建一个包罗万象的位置块,它将所有额外的查询直接传递给我们的应用程序。 我们将包含 /etc/nginx/uwsgi_params
中的 uwsgi
参数,并将流量传递到 uWSGI 服务器设置的套接字:
/etc/nginx/sites-available/firstsite
server { listen 80; server_name firstsite.com www.firstsite.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/sammy/firstsite; } location / { include uwsgi_params; uwsgi_pass unix:/run/uwsgi/firstsite.sock; } }
这样,我们的第一个服务器块就完成了。
我们将以此作为第二个项目的 Nginx 配置文件的基础。 现在复制过来:
sudo cp /etc/nginx/sites-available/firstsite /etc/nginx/sites-available/secondsite
在文本编辑器中打开新文件:
sudo nano /etc/nginx/sites-available/secondsite
在这里,您必须将对 firstsite
的任何引用更改为对 secondsite
的引用。 您还必须修改 server_name
以便您的第二个项目响应不同的域名或更改端口(如果您没有多个域名或 IP 地址)。 完成后,它将如下所示:
/etc/nginx/sites-available/secondsite
server { listen 80; server_name secondsite.com www.secondsite.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/sammy/secondsite; } location / { include uwsgi_params; uwsgi_pass unix:/run/uwsgi/secondsite.sock; } }
完成后保存并关闭文件。
接下来,将两个新配置文件链接到 Nginx 的 sites-enabled
目录以启用它们:
sudo ln -s /etc/nginx/sites-available/firstsite /etc/nginx/sites-enabled sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled
通过键入以下内容检查配置语法:
sudo nginx -t
如果未检测到语法错误,您可以重新启动 Nginx 服务以加载新配置:
sudo systemctl restart nginx
如果您还记得之前的内容,我们实际上从未启动过 uWSGI 服务器。 现在通过键入:
sudo systemctl start uwsgi
让我们删除端口 8080
的 UFW 规则,改为允许访问我们的 Nginx 服务器:
sudo ufw delete allow 8080 sudo ufw allow 'Nginx Full'
您现在应该能够通过访问它们各自的域名来访问您的两个项目。 公共和管理界面都应该按预期工作。
如果一切顺利,您可以通过键入以下命令启用这两个服务在启动时自动启动:
sudo systemctl enable nginx sudo systemctl enable uwsgi
笔记
配置 Nginx 后,下一步应该是使用 SSL/TLS 保护到服务器的流量。 这很重要,因为没有它,包括密码在内的所有信息都会以纯文本形式通过网络发送。
如果您有域名,获得 SSL 证书以保护您的流量的最简单方法是使用 Let's Encrypt。 按照 本指南 在 Ubuntu 16.04 上设置 Let's Encrypt with Nginx。
如果您没有域名,您仍然可以使用 自签名 SSL 证书 保护您的站点以进行测试和学习。
Nginx 和 uWSGI 故障排除
如果您无法访问您的应用程序,则需要对安装进行故障排除。
Nginx 显示默认页面而不是 Django 应用程序
如果 Nginx 显示默认页面而不是代理到您的应用程序,通常意味着您需要调整 /etc/nginx/sites-available/firstsite
文件中的 server_name
以指向您的服务器的 IP 地址或域名。
Nginx 使用 server_name
来确定使用哪个服务器块来响应请求。 如果您看到默认的 Nginx 页面,则表明 Nginx 无法将请求明确匹配到服务器块,因此它回退到 /etc/nginx/sites-available/default
中定义的默认块。
项目服务器块中的 server_name
必须比要选择的默认服务器块中的更具体。
Nginx 显示 502 Bad Gateway 错误而不是 Django 应用程序
502 错误表示 Nginx 无法成功代理请求。 各种配置问题都以 502 错误表示,因此需要更多信息才能正确排除故障。
查找更多信息的主要地方是 Nginx 的错误日志。 通常,这将告诉您在代理事件期间哪些条件导致了问题。 通过键入以下内容遵循 Nginx 错误日志:
sudo tail -F /var/log/nginx/error.log
现在,在浏览器中发出另一个请求以生成新的错误(尝试刷新页面)。 您应该会看到写入日志的新错误消息。 如果您查看该消息,它应该可以帮助您缩小问题范围。
您可能会看到以下一些消息:
connect() 到 unix:/run/uwsgi/firstsite.sock 失败(2:没有这样的文件或目录)
这表明 Nginx 无法在给定位置找到套接字文件。 您应该将 /etc/nginx/sites-available
文件中 firstsite
和 secondsite
文件中定义的 uwsgi_pass
位置与 firstsite.sock
的实际位置进行比较/run/uwsgi
目录中的 X149X] 套接字文件。
通过键入以下内容检查 /run/uwsgi
目录中是否存在套接字文件:
sudo ls /run/uwsgi
如果/run/uwsgi
中没有socket文件,一般说明uwsgi
进程无法创建。 检查 uwsgi
进程的状态,看看它是否能够启动:
sudo systemctl status uwsgi
如果 systemctl status
命令表明发生了错误,或者在目录中没有找到套接字文件,则表明 uWSGI 无法正确启动。 通过键入以下内容检查 uWSGI 进程日志:
sudo journalctl -u uwsgi
查看日志中的消息以找出 uWSGI 遇到问题的地方。 您可能遇到问题的原因有很多,但通常,如果 uWSGI 无法创建套接字文件,原因之一是:
- 项目文件由
root
用户而不是sudo
用户拥有 /etc/systemd/system/uwsgi.service
文件中的ExecStartPre
行不包含创建目录和分配所有权的正确命令/etc/nginx/sites-available
目录下站点配置文件中的uwsgi_pass
路径没有针对正确的socket位置/etc/uwsgi/sites
目录下.ini
文件中定义的uWSGI配置不正确。 检查以下项目: chdir 指令一旦被插值,就指向主项目目录。 home 指令一旦被插入,就指向虚拟环境目录。 module 指令使用 Python 模块导入语法从内部项目目录中加载 wsgi.py 文件。 socket 指令指向 /run/uwsgi 文件中的一个文件(应该由上述服务文件中的 ExecStartPre 行创建)。
如果您对 /etc/systemd/system/uwsgi.service
文件进行更改,请重新加载守护程序以重新读取服务定义并通过键入以下内容重新启动 uWSGI 进程:
sudo systemctl daemon-reload sudo systemctl restart uwsgi
修复这些问题应该允许 Nginx 正确找到套接字文件。
connect() 到 unix:/run/uwsgi/firstsite.sock 失败(13:权限被拒绝)
这表明 Nginx 由于权限问题无法连接到 uWSGI 套接字。 通常,当在受限环境中创建套接字或权限错误时会发生这种情况。 虽然 uWSGI 进程能够创建套接字文件,但 Nginx 无法访问它。
如果在根目录 (/
) 和套接字文件之间的任何点有有限的权限,就会发生这种情况。 通过将套接字文件的绝对路径传递给 namei
命令,我们可以查看套接字文件及其每个父目录的权限和所有权值:
namei -nom /run/uwsgi/firstsite.sock
Outputf: /run/uwsgi/firstsite.sock drwxr-xr-x root root / drwxr-xr-x root root run drwxr-xr-x sammy www-data uwsgi srw-rw---- sammy www-data firstsite.sock
输出显示每个目录组件的权限。 通过查看权限(第一列)、所有者(第二列)和组所有者(第三列),我们可以确定允许对套接字文件进行何种类型的访问。
在上面的示例中,指向套接字文件的每个目录都具有全局读取和执行权限(目录的权限列以 r-x
而不是 ---
结尾)。 www-data
组对套接字本身具有组所有权。 通过这些设置,Nginx 进程应该能够成功访问套接字。
如果任何通向套接字的目录不属于 www-data
组或没有全局读取和执行权限,则 Nginx 将无法访问套接字。 通常,这意味着配置文件有错误。
如果目录路径的权限或所有权过于严格,请查看 /etc/systemd/system/uwsgi.service
文件。 ExecStartPre
指令负责创建 /run/uwsgi
目录并将组所有权分配给 www-data
组。 如果此处的命令不正确,则目录路径可能过于严格。
如果 Nginx 进程无法访问套接字文件本身,则 /etc/uwsgi/sites
内的 .ini
文件中定义的设置可能不正确。 检查 chown-socket
和 chmod-socket
的值以确保 Web 进程被授予访问文件的权限。
进一步的故障排除
对于其他故障排除,日志可以帮助缩小根本原因。 依次检查它们中的每一个,并查找指示问题区域的消息。
以下日志可能会有所帮助:
- 检查 Nginx 进程日志,输入:
sudo journalctl -u nginx
- 通过键入以下内容检查 Nginx 访问日志:
sudo less /var/log/nginx/access.log
- 通过键入以下内容检查 Nginx 错误日志:
sudo less /var/log/nginx/error.log
- 通过键入以下命令检查 uWSGI 应用程序日志:
sudo journalctl -u uwsgi
当您更新配置或应用程序时,您可能需要重新启动流程以适应您的更改。
如果你更新你的 Django 应用程序,你可以通过键入以下命令重新启动 uWSGI 进程以获取更改:
sudo systemctl restart uwsgi
如果您更改 uwsgi
systemd 服务文件,请重新加载守护程序并通过键入以下内容重新启动该进程:
sudo systemctl daemon-reload sudo systemctl restart uwsgi
如果您更改 Nginx 服务器块配置,请测试配置,然后输入以下命令来测试 Nginx:
sudo nginx -t && sudo systemctl restart nginx
这些命令有助于在您调整配置时获取更改。
结论
在本指南中,我们设置了两个 Django 项目,每个项目都在自己的虚拟环境中。 我们已经将 uWSGI 配置为使用为每个项目配置的虚拟环境独立地为每个项目提供服务。 之后,我们设置 Nginx 作为反向代理来处理客户端连接并根据客户端请求为正确的项目提供服务。
Django 通过提供许多通用部分使创建项目和应用程序变得简单,让您可以专注于独特的元素。 通过利用本文中描述的通用工具链,您可以轻松地为您从单个服务器创建的应用程序提供服务。