前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何在Ubuntu 16.04上使用uWSGI和Nginx为Django应用程序提供服务

如何在Ubuntu 16.04上使用uWSGI和Nginx为Django应用程序提供服务

原创
作者头像
尘埃
修改2018-10-22 11:38:46
4.2K0
修改2018-10-22 11:38:46
举报

介绍

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

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

准备和目标

一台已经设置好可以使用sudo命令的非root账号的Ubuntu服务器,并且已开启防火墙。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器

我们将在两个不同的虚拟环境中安装Django。这将允许您的项目及其要求单独处理。我们将创建两个示例项目,以便我们可以在多项目环境中执行这些步骤。

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

让我们开始吧。

安装和配置VirtualEnv和VirtualEnvWrapper

我们将在他们自己的虚拟环境中安装我们的Django项目,以隔离每个项目的需求。为此,我们将进行安装virtualenv,这可以创建Python虚拟环境,并且安装可以为virtualenv工作流程增加一些可用性改进的virtualenvwrapper

我们将使用pipPython包管理器安装这两个组件。我们可以从Ubuntu存储库安装此实用程序。

如果要使用Python 2构建Django项目,请键入:

代码语言:javascript
复制
sudo apt-get update
sudo apt-get install python-pip

如果您使用的是Python 3,请键入:

代码语言:javascript
复制
sudo apt-get update
sudo apt-get install python3-pip

现在,您已经安装了pip,我们可以安装全局性安装virtualenvvirtualenvwrapper。我们还将使用pip自己升级pip到最新版本。

如果您使用的是Python 2,请键入:

代码语言:javascript
复制
sudo -H pip install --upgrade pip
sudo -H pip install virtualenv virtualenvwrapper

如果您使用的是Python 3,请键入:

代码语言:javascript
复制
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenv virtualenvwrapper

安装这些组件后,我们现在可以使用virtualenvwrapper脚本配置所需的信息来配置shell 。我们的虚拟环境将全部放在我们的主文件夹Env中的一个目录中,以便于访问。这是通过一个名为WORKON_HOME的环境变量配置的。我们可以将它添加到我们的shell初始化脚本中,并可以获取虚拟环境包装器脚本。

如果您使用的是Python 3pip3命令,则还需要在shell初始化脚本中添加一行:

代码语言:javascript
复制
echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.bashrc

无论您使用的是哪个版本的Python,都需要运行以下命令:

代码语言:javascript
复制
echo "export WORKON_HOME=~/Env" >> ~/.bashrc
echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc

现在,请获取shell初始化脚本,以便在当前会话中使用此功能:

代码语言:javascript
复制
source ~/.bashrc

您现在应该在主文件夹中调用Env目录,该目录将保存虚拟环境信息。

创建Django项目

现在我们有了虚拟环境工具,我们将创建两个虚拟环境,在每个环境中安装Django,并启动两个项目。

创建第一个项目

我们可以使用virtualenvwrapper脚本提供给我们的一些命令轻松创建虚拟环境。

键入以下内容,使用您的第一个站点或项目的名称创建您的第一个虚拟环境:

代码语言:javascript
复制
mkvirtualenv firstsite

这将创建一个虚拟环境,在其中安装Python和pip ,并激活环境。您的提示将更改为表示您现在正在新的虚拟环境中运行。它看起来像这样:。括号中的值是虚拟环境的名称。现在安装的任何软件都将安装到虚拟环境中,而不是安装在全局系统上。这允许我们在每个项目的基础上隔离我们的包。(firstsite)user@hostname:~$``pip

我们的第一步是安装Django本身。我们可以使用pip安装它,不需要sudo权限是因为我们在虚拟环境中本地安装它:

代码语言:javascript
复制
pip install django

安装Django后,我们可以通过键入以下内容来创建第一个示例项目:

代码语言:javascript
复制
cd ~
django-admin.py startproject firstsite

这将创建一个在您的主目录中调用的firstsite目录。其中包括用于处理项目各个方面的管理脚本以及用于存放实际项目代码的另一个同名目录。

进入第一级目录,以便我们可以开始为示例项目设置最低要求。

代码语言:javascript
复制
cd ~/firstsite

首先迁移数据库以初始化我们的项目将使用的SQLite数据库。如果您愿意,可以为应用程序设置备用数据库,但这超出了本指南的范围:

代码语言:javascript
复制
~/firstsite/manage.py migrate

您现在应该在项目目录中调用一个名为db.sqlite3的数据库文件。现在,我们可以通过输入以下内容来创建管理用户

代码语言:javascript
复制
~/firstsite/manage.py createsuperuser

此时,您的项目目录(在我们的示例中是~/firstsite)应具有以下内容:

  • ~/firstsite/manage.py:Django项目管理脚本。
  • ~/firstsite/firstsite/:Django项目包。这应该包括__init__.pysettings.pyurls.py,和wsgi.py文件。
  • ~/firstsite/db.sqlite3:用于存储站点信息的SQLite数据库文件。

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

代码语言:javascript
复制
nano ~/firstsite/firstsite/settings.py

首先找到ALLOWED_HOSTS指令。这定义了可用于连接Django实例的服务器地址或域名列表。具有不在此列表中的主机头的任何传入请求都将引发异常。Django要求您将其设置为防止某类安全漏洞。

在方括号中,列出与Django服务器关联的IP地址或域名。每个项目都应该在引号中列出,条目用逗号分隔。如果您希望请求整个域和任何子域,请在条目的开头添加一个句点。在下面的代码段中,有一些注释掉的示例用于演示:

代码语言:javascript
复制
. . .
# 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项目基本目录中调用的目录中。将此行添加到文件的底部以配置此行为:

代码语言:javascript
复制
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

完成后保存并关闭文件。现在,收集我们网站的静态元素,并输入以下内容将它们放在该目录中:

代码语言:javascript
复制
~/firstsite/manage.py collectstatic

可能会要求您输入“是”以确认操作并收集静态内容。将在项目目录中调用一个新目录static

接下来,我们可以打开一个端口,以便我们可以访问Django开发服务器。如果您按照初始服务器设置指南进行操作,则应启用UFW防火墙。键入以下内容允许连接到端口8080:

代码语言:javascript
复制
sudo ufw allow 8080

完成所有这些后,我们可以通过临时启动开发服务器来测试我们的项目。类型:

代码语言:javascript
复制
~/firstsite/manage.py runserver 0.0.0.0:8080

这将启动端口上的开发服务器8080。访问您服务器的域名或IP地址,然后8080在浏览器中访问:

代码语言:javascript
复制
http://server_domain_or_IP:8080

你应该看到一个如下所示的页面:

/admin在浏览器的地址栏中添加到URL的末尾,您将进入管理员登录页面:

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

在测试此功能后,通过在终端中键入CTRL-C来停止开发服务器。我们现在可以继续我们的第二个项目。

创建第二个项目

第二个项目的创建方式与第一个项目完全相同。我们将在本节中删除解释,看看你是如何完成这一次的。

移回主目录并为新项目创建第二个虚拟环境。一旦激活,就在这个新环境中安装Django:

代码语言:javascript
复制
cd ~
mkvirtualenv secondsite
pip install django

新的环境将被创建改变,你离开以前的虚拟环境。这个Django实例完全独立于您配置的另一个实例。这允许您独立管理它们并根据需要进行自定义。

创建第二个项目并进入项目目录:

代码语言:javascript
复制
cd ~
django-admin.py startproject secondsite
cd ~/secondsite

初始化数据库并创建管理用户:

代码语言:javascript
复制
~/secondsite/manage.py migrate
~/secondsite/manage.py createsuperuser

打开设置文件:

代码语言:javascript
复制
nano ~/secondsite/secondsite/settings.py

ALLOWED_HOSTS设置为第二个项目的域,服务器的IP地址或两者,就像您对第一个项目所做的那样:

代码语言:javascript
复制
ALLOWED_HOSTS = ['second_project_domain_or_IP', 'another_domain_or_IP', . . .]

添加静态文件的位置,就像在上一个项目中一样:

代码语言:javascript
复制
. . .
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

保存并关闭文件。现在,通过键入以下内容将静态元素收集到该目录中:

代码语言:javascript
复制
~/secondsite/manage.py collectstatic

最后,启动开发服务器以测试该站点:

代码语言:javascript
复制
~/secondsite/manage.py runserver 0.0.0.0:8080

你应该检查常规网站:

代码语言:javascript
复制
http://server_domain_or_IP:8080

还要登录管理站点:

代码语言:javascript
复制
http://server_domain_or_IP:8080/admin

当您确认所有内容都按预期工作后,在终端中键入CTRL-C以停止开发服务器。

退出虚拟环境

由于我们现在完成了指南的Django部分,我们可以停用我们的第二个虚拟环境:

代码语言:javascript
复制
deactivate

如果您需要再次使用任何一个Django站点,则应重新激活其各自的环境。您可以使用以下workon命令执行此操作:

代码语言:javascript
复制
workon firstsite

要么:

代码语言:javascript
复制
workon secondsite

再次,在您完成网站工作后停用:

代码语言:javascript
复制
deactivate

我们现在可以继续配置应用程序服务器。

设置uWSGI Application Server

现在我们已经准备好了两个Django项目,我们可以配置uWSGI。uWSGI是一个应用程序服务器,可以通过名为WSGI的标准接口与应用程序进行通信。

安装uWSGI

与上面链接的指南不同,在本教程中,我们将全局安装uWSGI。这将减少处理多个Django项目的摩擦。在我们安装uWSGI之前,我们需要软件所依赖的Python开发文件。我们可以直接从Ubuntu的存储库安装它。

如果您在Python 2中使用Django ,请键入:

代码语言:javascript
复制
sudo apt-get install python-dev

如果您使用的是Python 3,请键入:

代码语言:javascript
复制
sudo apt-get install python3-dev

现在开发文件可用,我们可以通过全局安装uWSGI pip

如果您使用的是Python 2,请键入:

代码语言:javascript
复制
sudo -H pip install uwsgi

如果您使用的是Python 3,请键入:

代码语言:javascript
复制
sudo -H pip3 install uwsgi

我们可以通过传递我们其中一个站点的信息来快速测试该应用程序服务器。例如,我们可以通过输入以下内容告诉它为我们的第一个项目服务:

代码语言:javascript
复制
uwsgi --http :8080 --home /home/sammy/Env/firstsite --chdir /home/sammy/firstsite -w firstsite.wsgi

在这里,我们告诉uWSGI使用位于我们~/Env目录中的虚拟环境,更改为项目目录,并使用wsgi.py存储在内部firstsite目录中的文件来提供文件(使用firstsite.wsgiPython模块语法)。对于我们的演示,我们告诉它在端口上提供HTTP服务8080

如果您在浏览器中转到服务器的域名或IP地址,然后:8080再次显示您的站点(/admin界面中的静态元素,如CSS,将无法使用)。完成此功能的测试后,在终端中键入CTRL-C。

创建配置文件

从命令行运行uWSGI对于测试很有用,但对实际部署不是特别有用。相反,我们将以“Emperor模式”运行uWSGI,它允许主进程在给定一组配置文件的情况下自动管理单独的应用程序。

创建一个用于保存配置文件的目录。由于这是一个全局过程,我们将创建一个名为/etc/uwsgi/sites存储配置文件的目录:

代码语言:javascript
复制
sudo mkdir -p /etc/uwsgi/sites

在此目录中,我们将放置配置文件。我们需要为我们服务的每个项目配置一个配置文件。uWSGI进程可以采用各种格式的配置文件,但.ini由于它们的简单性,我们将使用文件。

为您的第一个项目创建一个文件,并在文本编辑器中打开它:

代码语言:javascript
复制
sudo nano /etc/uwsgi/sites/firstsite.ini

在里面,我们必须从[uwsgi]节标题开始。我们所有的信息都将在此标题下方。我们还将使用变量使我们的配置文件更具可重用性。在标题之后,设置一个名为project第一个项目名称的变量。添加一个名为uid的变量来保存您的sudo用户名。

我们还将添加一个使用用户主目录路径调用的变量base。这将使用我们使用%(variable_name)语法设置的用户名构建。读取配置时,这将被变量的值替换:

代码语言:javascript
复制
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)

接下来,我们需要配置uWSGI,以便它正确处理我们的项目。我们需要通过设置chdir选项来更改为根项目目录。我们可以使用相同的变量语法组合主目录和项目名称。

以类似的方式,我们将指出我们项目的虚拟环境。通过设置模块,我们可以准确地指出如何与我们的项目进行交互(通过从我们的内部项目目录wsgi.py文件中导入可调用的“应用程序” )。这些项的配置如下所示:

代码语言:javascript
复制
[uwsgi]
project = firstsite
uid = sammy
base = /home/%(uid)

chdir = %(base)/%(project)
home = %(base)/Env/%(project)
module = %(project).wsgi:application

我们想要创建一个包含5个工作者的主进程。我们可以通过添加以下内容来实现:

代码语言:javascript
复制
[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选项,以便在服务停止时自动清除套接字文件:

代码语言:javascript
复制
[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配置就完成了。保存并关闭文件。

使用变量设置文件的优点是它使重用变得非常简单。复制第一个项目的配置文件,以用作第二个配置文件的基础:

代码语言:javascript
复制
sudo cp /etc/uwsgi/sites/firstsite.ini /etc/uwsgi/sites/secondsite.ini

使用文本编辑器打开第二个配置文件:

代码语言:javascript
复制
sudo nano /etc/uwsgi/sites/secondsite.ini

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

代码语言:javascript
复制
[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

代码语言:javascript
复制
sudo nano /etc/systemd/system/uwsgi.service

从该[Unit]部分开始,该部分用于指定元数据和订购信息。我们在这里简单介绍一下我们的服务:

代码语言:javascript
复制
[Unit]
Description=uWSGI Emperor service

接下来,我们将打开该[Service]部分。我们将使用该ExecStartPre指令设置运行服务器所需的部分。这将确保创建/run/uwsgi目录,并且我们的普通用户拥有该目录,并将该www-data组作为组所有者。同时用-p标志的mkdirchown命令成功返回即使不需要他们的操作。这就是我们想要的。

对于ExecStart指令指定的实际启动命令,我们将指向uwsgi可执行文件。我们将告诉它以“Emperor模式”运行,允许它使用它找到的文件管理多个应用程序/etc/uwsgi/sites。我们还将添加systemd正确管理流程所需的部分。这里是从uWSGI得到的资料。

代码语言:javascript
复制
[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]部分。这允许我们指定何时应该自动启动服务。我们将服务绑定到多用户系统状态。无论何时为多个用户设置系统(正常运行条件),我们的服务都将被激活:

代码语言:javascript
复制
[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的默认存储库下载:

代码语言:javascript
复制
sudo apt-get install nginx

一旦安装了Nginx,我们就可以继续为每个项目创建一个服务器块配置文件。通过创建服务器块配置文件从第一个项目开始:

代码语言:javascript
复制
sudo nano /etc/nginx/sites-available/firstsite

在内部,我们可以通过指示应该可以访问第一个项目的端口号和域名来启动我们的服务器块。该server_name必须与服务器的某个域名或其IP地址匹配,否则可能会使用默认的Nginx页面。我们假设您拥有每个域名:

代码语言:javascript
复制
server {
    listen 80;
    server_name firstsite.com www.firstsite.com;
}

接下来,我们可以告诉Nginx不要担心它是否找不到图标。我们还将它指向静态文件目录的位置,我们收集了站点的静态元素:

代码语言:javascript
复制
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;
    }
}

接下来,我们可以创建一个catch-all位置块,将所有其他查询直接传递给我们的应用程序。我们将包含在/etc/nginx/uwsgi_params中的参数uwsgi并将流量传递给uWSGI服务器设置的套接字:

代码语言:javascript
复制
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配置文件的基础。立即复制:

代码语言:javascript
复制
sudo cp /etc/nginx/sites-available/firstsite /etc/nginx/sites-available/secondsite

在文本编辑器中打开新文件:

代码语言:javascript
复制
sudo nano /etc/nginx/sites-available/secondsite

在这里,你必须任何引用更改为firstsite与一个参考secondsite。您还必须修改server_name,以便您的第二个项目响应不同的域名,或者如果您没有多个域名或IP地址,则更改端口。完成后,它看起来像这样:

代码语言:javascript
复制
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目录以启用它们:

代码语言:javascript
复制
sudo ln -s /etc/nginx/sites-available/firstsite /etc/nginx/sites-enabled
sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled

键入以下命令检查配置语法:

代码语言:javascript
复制
sudo nginx -t

如果未检测到语法错误,则可以重新启动Nginx服务以加载新配置:

代码语言:javascript
复制
sudo systemctl restart nginx

如果你早些时候记得,我们从未真正启动过uWSGI服务器。现在输入以下命令:

代码语言:javascript
复制
sudo systemctl start uwsgi

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

代码语言:javascript
复制
sudo ufw delete allow 8080
sudo ufw allow 'Nginx Full'

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

如果顺利,您可以通过键入以下命令启用两个服务以在引导时自动启动:

代码语言:javascript
复制
sudo systemctl enable nginx
sudo systemctl enable uwsgi

注意

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

对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错误日志:

代码语言:javascript
复制
sudo tail -F /var/log/nginx/error.log

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

您可能会看到以下消息:

connect()到unix:/run/uwsgi/firstsite.sock失败(2:没有这样的文件或目录)

这表明Nginx无法在给定位置找到套接字文件。你应该比较/etc/nginx/sites-available文件中firstsitesecondsite文件所定义的uwsgi_pass位置文件与在/run/uwsgi目录firstsite.socksecondsite.sock套接字文件的的实际位置。

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

代码语言:javascript
复制
sudo ls /run/uwsgi

如果/run/uwsgi没有套接字文件,通常意味着该uwsgi进程无法创建它。检查uwsgi进程的状态以确定它是否能够启动:

代码语言:javascript
复制
sudo systemctl status uwsgi

如果该systemctl status命令指示发生错误或者您未在目录中找到套接字文件,则表明uWSGI无法正确启动。键入以下命令检查uWSGI进程日志:

代码语言:javascript
复制
sudo journalctl -u uwsgi

查看日志中的消息,找出uWSGI遇到问题的位置。您可能遇到问题的原因有很多,但通常情况下,如果uWSGI无法创建套接字文件,则出于以下原因之一:

  • 项目文件由root用户而不是sudo用户拥有
  • 文件中的ExecStartPre/etc/systemd/system/uwsgi.service不包含用于创建目录和分配所有权的正确命令
  • 将在该网站/etc/nginx/sites-available目录的uwsgi_pass配置文件路径的目标不是正确的插槽位置
  • /etc/uwsgi/sites目录中.ini 文件中定义的uWSGI配置不正确。检查以下项目:
    • chdir指令一旦插值,就指向主项目目录。
    • home指令一旦插值,就指向虚拟环境目录。
    • module指令使用Python模块导入语法wsgi.py从内部项目目录中加载文件。
    • socket指令指向文件中的/run/uwsgi文件(应该由ExecStartPre上面提到的服务文件中的行创建)。

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

代码语言:javascript
复制
sudo systemctl daemon-reload
sudo systemctl restart uwsgi

修复这些问题应该允许Nginx正确找到套接字文件。

connect()到unix:/run/uwsgi/firstsite.sock失败(13:权限被拒绝)

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

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

代码语言:javascript
复制
namei -nom /run/uwsgi/firstsite.sock
代码语言:javascript
复制
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进程无法访问套接字文件本身,则其中的.ini文件中定义的设置/etc/uwsgi/sites可能不正确。检查值chown-socketchmod-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进程以获取更改:

代码语言:javascript
复制
sudo systemctl restart uwsgi

如果更改uwsgisystemd服务文件,请重新加载守护程序并键入以下命令重新启动该过程:

代码语言:javascript
复制
sudo systemctl daemon-reload
sudo systemctl restart uwsgi

如果您更改Nginx服务器块配置,请通过键入以下内容来测试配置,然后测试Nginx:

代码语言:javascript
复制
sudo nginx -t && sudo systemctl restart nginx

这些命令有助于在调整配置时获取更改。

结论

在本指南中,我们设置了两个Django项目,每个项目都在自己的虚拟环境中。我们已将uWSGI配置为使用为每个项目配置的虚拟环境独立地为每个项目提供服务。之后,我们设置Nginx作为反向代理来处理客户端连接并根据客户端请求提供正确的项目。

Django通过提供许多常见的部分使创建项目和应用程序变得简单,使您可以专注于独特的元素。通过利用本文中介绍的常规工具链,您可以轻松地为从单个服务器创建的应用程序提供服务。

更多Ubuntu教程请前往腾讯云+社区学习更多知识。


参考文献:《How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
    • 准备和目标
      • 安装和配置VirtualEnv和VirtualEnvWrapper
        • 创建Django项目
          • 创建第一个项目
          • 创建第二个项目
          • 退出虚拟环境
        • 设置uWSGI Application Server
          • 安装uWSGI
          • 创建配置文件
          • 为uWSGI创建systemd单元文件
        • 安装和配置Nginx作为反向代理
          • 对Nginx和uWSGI进行故障排除
            • Nginx显示默认页面而不是Django应用程序
            • Nginx显示502 Bad Gateway错误而不是Django应用程序
            • 进一步排除故障
          • 结论
          相关产品与服务
          SSL 证书
          腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档