文章内容

2018/5/18 17:56:48,作 者: 黄兵

How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04

介绍

Django是一个功能强大的Web框架,可以帮助您将Python应用程序或网站打开。 Django包含一个简化的开发服务器,用于在本地测试您的代码,但对于与生产相关的任何事情,都需要更安全和更强大的Web服务器。

在本指南中,我们将演示如何在Ubuntu 16.04上安装和配置一些组件以支持和服务Django应用程序。我们将配置uWSGI应用程序容器服务器以与我们的应用程序进行交互。然后,我们将设置Nginx来反向代理uWSGI,使我们能够访问其安全和性能功能来为我们的应用程序提供服务。

先决条件和目标

为了完成本指南,您应该有一个全新的Ubuntu 16.04服务器实例,并配置了一个非root用户,并配置了sudo权限。 您可以通过运行我们的初始服务器设置指南来了解如何进行设置。

我们将在两个不同的虚拟环境中安装Django。 这将允许您的项目和他们的要求分开处理。 我们将创建两个示例项目,以便我们可以贯穿多项目环境中的步骤。

一旦我们有我们的应用程序,我们将安装和配置uWSGI应用程序服务器。 这将作为我们应用程序的接口,它将使用HTTP将客户端请求转换为我们的应用程序可以处理的Python调用。 然后,我们将在uWSGI之前设置Nginx,以利用其高性能连接处理机制和易于实现的安全功能。

我们开始吧!

安装并配置VirtualEnv和VirtualEnvWrapper

我们将在他们自己的虚拟环境中安装我们的Django项目,以隔离每个项目的需求。 为此,我们将安装可以创建Python虚拟环境的virtualenv和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: A Django project management script.
  • ~/firstsite/manage.py: Django项目的管理脚本。
  • ~/firstsite/firstsite/: The Django project package. This should contain the __init__.pysettings.pyurls.py, and wsgi.py files.
  • ~/firstsite/firstsite/: Django项目包,包括__init__.pysettings.pyurls.py,和 wsgi.py文件。
  • ~/firstsite/db.sqlite3: The SQLite database file used to store your site information.
  • ~/firstsite/db.sqlite3: SQLite 数据库存储你的站点信息。

接下来,使用文本编辑器打开项目的设置文件:

  • nano ~/firstsite/firstsite/settings.py

从查找ALLOWED_HOSTS指令开始。 这定义了可用于连接到Django实例的服务器地址或域名列表。 具有不在此列表中的主机头的任何传入请求都会引发异常。 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

你将会看到如下内容:

Django sample site

将/ admin添加到浏览器地址栏中的网址末尾,然后转到管理员登录页面:

Django admin login

使用您通过createsuperuser命令选择的管理登录凭证,登录到服务器。 您将可以访问管理界面:

Django admin interface

在测试完此功能之后,通过在终端中输入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的仓库安装。

如果你使用的是Python2,输入如下内容:

  • sudo apt-get install python-dev

如果你使用的是Python3,输入如下内容:

  • sudo apt-get install python3-dev

既然开发文件可用,我们可以通过pip全局安装uWSGI。

如果你使用的是Python2,输入如下内容:

  • sudo -H pip install uwsgi


果你使用的是Python3,输入如下内容:

  • sudo -H pip3 install uwsgi

我们可以通过向我们的某个网站传递信息来快速测试此应用程序服务器。 例如,我们可以通过键入以下内容来告诉它为我们的第一个项目服务

  • uwsgi --http :8080 --home /home/sammy/Env/firstsite --chdir /home/sammy/firstsite -w firstsite.wsgi

在这里,我们告诉uWSGI使用我们的〜/ Env目录中的虚拟环境,切换到我们项目的目录,并使用存储在内部第一站点目录中的wsgi.py文件来为文件提供服务(使用第一站点。 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

我们只需要更改此文件中的单个值,以使其适用于我们的第二个项目。 使用您用于第二个项目的名称修改项目变量:

/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 emperor进程,并在启动时自动启动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和chowncommand也会成功返回。 这是我们想要的。

对于由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

在这里,您必须更改对第一站点的引用并引用第二站点。 您还必须修改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的启用站点的目录以启用它们:

  • 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

让我们将UFW规则删除到端口8080,而是允许访问我们的Nginx服务器:

  • sudo ufw delete allow 8080
  • sudo ufw allow 'Nginx Full'

您现在应该可以通过转到各自的域名来访问您的两个项目。 公共和管理界面都应按预期工作。

如果这一切顺利,您可以通过输入以下命令启用两项服务:

  • sudo systemctl enable nginx
  • sudo systemctl enable uwsgi
Note

配置Nginx后,下一步应该是使用SSL / TLS将流量保护到服务器。 这很重要,因为没有它,所有信息(包括密码)都将以纯文本的形式通过网络发送。

如果您有域名,获取SSL证书以保护您的流量的最简单方法是使用Let's Encrypt。 按照本指南设置让我们在Ubuntu 16.04上使用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必须比要选择的默认服务器块中的server_name更具体。

Nginx显示502错误的网关错误,而不是Django应用程序

502错误表示Nginx无法成功代理请求。各种各样的配置问题都以502错误表达,因此需要更多信息才能正确排除故障。

查找更多信息的主要位置在Nginx的错误日志中。一般来说,这会告诉你在代理事件期间哪些情况会导致问题。输入以下命令来跟踪Nginx错误日志:

  • sudo tail -F /var/log/nginx/error.log

现在,在浏览器中发出另一个请求以生成新的错误(尝试刷新页面)。 您应该看到写入日志的新错误消息。 如果你看看这个信息,它应该可以帮助你缩小问题的范围。

您可能会看到以下一些消息:

connect() to unix:/run/uwsgi/firstsite.sock failed (2: No such file or directory)

这表明Nginx无法在给定位置找到套接字文件。 您应该将/ etc / nginx / sites-available文件中第一个站点和第二个站点文件中定义的uwsgi_pass位置与/ run / uwsgi目录中firstsite.sock和secondsite.sock套接字文件的实际位置进行比较。

通过输入以下命令来检查/ run / uwsgi目录中是否存在套接字文件:

  • sudo ls /run/uwsgi

如果/ run / uwsgi中没有套接字文件,通常意味着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路径未针对正确的套接字位置
  • The uWSGI configuration defined in the .ini files within the /etc/uwsgi/sites directory is incorrect. Check the following items:
    • 在/ etc / uwsgi / sites目录内的.ini文件中定义的uWSGI配置不正确。检查以下项目:
    • chdir指令一旦插入,指向主项目目录。
    • home指令插入后指向虚拟环境目录。
    • 模块指令使用Python模块导入语法从内部项目目录中加载wsgi.py文件。
    • socket指令指向/ run / uwsgi文件中的一个文件(应由上述服务文件中的ExecStartPre行创建)。

如果您对/etc/systemd/system/uwsgi.service文件进行了更改,请重新加载守护程序以重新读取服务定义,然后键入以下命令重新启动uWSGI进程:

  • sudo systemctl daemon-reload
  • sudo systemctl restart uwsgi

解决这些问题应该允许Nginx正确地找到套接字文件。

connect() to unix:/run/uwsgi/firstsite.sock failed (13: Permission denied)

这表明由于权限问题,Nginx无法连接到uWSGI套接字。 通常,这是在套接字在受限环境中创建或权限错误时发生的。 虽然uWSGI进程能够创建套接字文件,但Nginx无法访问它。

如果在根目录(/)套接字文件之间的任何点上的权限有限,就会发生这种情况。 通过将绝对路径传递给我们的套接字文件到namei命令,我们可以看到套接字文件及其每个父目录的权限和所有权值:

  • namei -nom /run/uwsgi/firstsite.sock
Output
f: /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通过提供许多常用的部分使得创建项目和应用程序变得简单,让您专注于独特的元素。 通过利用本文中介绍的通用工具链,您可以轻松地为从单个服务器创建的应用程序提供服务。

本文转载自:How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04

分享到:

发表评论

评论列表