如何在CentOS7上使用uWSGI和Nginx服务Django应用程序
介绍
Django 是一个强大的 Web 框架,可以帮助您启动 Python 应用程序或网站。 Django 包含一个简化的开发服务器,用于在本地测试您的代码,但对于任何与生产相关的事情,都需要一个更安全、更强大的 Web 服务器。
在本指南中,我们将演示如何在 CentOS 7 上安装和配置一些组件以支持和服务 Django 应用程序。 我们将配置 uWSGI 应用程序容器服务器以与我们的应用程序交互。 然后,我们将设置 Nginx 以反向代理到 uWSGI,使我们能够访问其安全性和性能特性来为我们的应用程序提供服务。
先决条件和目标
为了完成本指南,您应该拥有一个全新的 CentOS 7 服务器实例,该实例具有配置了 sudo
权限的非 root 用户。 您可以通过我们的 初始服务器设置指南 来了解如何设置它。
我们将在两个不同的虚拟环境中安装 Django。 这将允许单独处理您的项目及其要求。 我们将创建两个示例项目,以便我们可以在多项目环境中运行这些步骤。
一旦我们有了我们的应用程序,我们将安装和配置 uWSGI 应用程序服务器。 这将作为我们应用程序的接口,它将使用 HTTP 的客户端请求转换为我们的应用程序可以处理的 Python 调用。 然后,我们将在 uWSGI 前面设置 Nginx,以利用其高性能的连接处理机制和易于实现的安全特性。
让我们开始吧。
安装和配置 VirtualEnv 和 VirtualEnvWrapper
我们将在他们自己的虚拟环境中安装我们的 Django 项目,以隔离每个项目的需求。 为此,我们将安装 virtualenv
,它可以创建 Python 虚拟环境,以及 virtualenvwrapper
,它为 virtualenv
工作流程增加了一些可用性改进。
我们将使用 Python 包管理器 pip
安装这两个组件。 要获得 pip
,我们首先需要启用 EPEL 存储库。 我们可以通过键入以下内容轻松完成此操作:
sudo yum install epel-release
启用 EPEL 后,我们可以通过键入以下命令安装 pip
:
sudo yum install python-pip
现在您已经安装了 pip
,我们可以通过键入以下命令全局安装 virtualenv
和 virtualenvwrapper
:
sudo pip install virtualenv virtualenvwrapper
安装这些组件后,我们现在可以使用 virtualenvwrapper
脚本所需的信息来配置我们的 shell。 我们的虚拟环境都将放置在我们的主文件夹中名为 Env
的目录中,以便于访问。 这是通过一个名为 WORKON_HOME
的环境变量来配置的。 我们可以将它添加到我们的 shell 初始化脚本中,并且可以获取虚拟环境包装器脚本。
要将适当的行添加到 shell 初始化脚本,您需要运行以下命令:
echo "export WORKON_HOME=~/Env" >> ~/.bashrc echo "source /usr/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 数据库。 如果您愿意,您可以为您的应用程序设置一个备用数据库,但这超出了本指南的范围:
./manage.py migrate
您现在应该在项目目录中有一个名为 db.sqlite3
的数据库文件。 现在,我们可以通过键入以下内容来创建管理用户:
./manage.py createsuperuser
您必须选择用户名,提供联系电子邮件地址,然后选择并确认密码。
接下来,使用文本编辑器打开项目的设置文件:
nano firstsite/settings.py
由于我们将设置 Nginx 来为我们的网站提供服务,我们需要配置一个目录来保存我们网站的静态资产。 这将允许 Nginx 直接为这些服务,这将对性能产生积极影响。 我们将告诉 Django 将它们放入项目基目录中名为 static
的目录中。 将此行添加到文件底部以配置此行为:
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
完成后保存并关闭文件。 现在,收集我们网站的静态元素并将它们放在该目录中,输入:
./manage.py collectstatic
您可以键入“是”以确认操作并收集静态内容。 在您的项目目录中将有一个名为 static
的新目录。
完成所有这些后,我们可以通过临时启动开发服务器来测试我们的项目。 类型:
./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 实例与您配置的另一个实例完全分开。 这使您可以独立管理它们并根据需要进行自定义。
创建第二个项目并进入项目目录:
django-admin.py startproject secondsite cd ~/secondsite
初始化数据库并创建一个管理用户:
./manage.py migrate ./manage.py createsuperuser
打开设置文件:
nano secondsite/settings.py
添加静态文件的位置,就像您在上一个项目中所做的那样:
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
保存并关闭文件。 现在,通过键入以下命令将静态元素收集到该目录中:
./manage.py collectstatic
最后,启动开发服务器来测试站点:
./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 开发文件。 我们还需要一个编译器。 我们可以使用 yum
获得这两个:
sudo yum install python-devel gcc
现在开发文件可用,我们可以通过 pip
全局安装 uWSGI,输入:
sudo pip install uwsgi
我们可以通过将我们的站点之一的信息传递给它来快速测试这个应用程序服务器。 例如,我们可以通过键入以下命令告诉它为我们的第一个项目服务:
uwsgi --http :8080 --home /home/user/Env/firstsite --chdir /home/user/firstsite -w firstsite.wsgi
在这里,我们告诉 uWSGI 使用位于我们的 ~/Env
目录中的虚拟环境,切换到我们的项目目录,并使用存储在我们内部 [X186X 中的 wsgi.py
文件] 目录来提供文件。 对于我们的演示,我们告诉它在端口 8080
上提供 HTTP。 如果您在浏览器中访问服务器的域名或 IP 地址,然后输入 :8080
,您将再次看到您的站点(/admin
界面中的静态元素还不能工作)。 完成此功能的测试后,在终端中键入 CTRL-C。
创建配置文件
从命令行运行 uWSGI 对于测试很有用,但对于实际部署并不是特别有用。 相反,我们将在“Emperor 模式”下运行 uWSGI,它允许主进程在给定一组配置文件的情况下自动管理单独的应用程序。
创建一个存放配置文件的目录。 由于这是一个全局进程,我们将创建一个名为 /etc/uwsgi/sites
的目录来存储我们的配置文件。 创建后进入目录:
sudo mkdir -p /etc/uwsgi/sites cd /etc/uwsgi/sites
在这个目录中,我们将放置我们的配置文件。 我们需要为我们服务的每个项目提供一个配置文件。 uWSGI 进程可以采用多种格式的配置文件,但由于其简单性,我们将使用 .ini
文件。
为您的第一个项目创建一个文件并在文本编辑器中打开它:
sudo nano firstsite.ini
在内部,我们必须从 [uwsgi]
节标题开始。 我们所有的信息都将放在此标题下方。 我们还将使用变量来使我们的配置文件更可重用。 在标题之后,使用您的第一个项目的名称设置一个名为 project
的变量。 使用拥有项目文件的普通用户名设置另一个变量。 添加一个名为 base
的变量,它使用您的用户名建立用户主目录的路径:
[uwsgi] project = firstsite username = user base = /home/%(username)
接下来,我们需要配置 uWSGI 以便它正确处理我们的项目。 我们需要通过设置 chdir
选项进入项目根目录。 我们可以使用 %(variable_name)
语法来组合我们之前设置的主目录和项目名称设置。 读取配置时,这将被变量的值替换。
以类似的方式,我们将为我们的项目指明虚拟环境。 通过设置模块,我们可以准确地指示如何与我们的项目交互(通过从项目目录中的 wsgi.py
文件中导入可调用的“应用程序”)。 这些项目的配置将如下所示:
[uwsgi] project = firstsite username = user base = /home/%(username) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application
我们想创建一个有 5 个工作人员的主进程。 我们可以通过添加这个来做到这一点:
[uwsgi] project = firstsite username = user base = /home/%(username) 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 服务器写入权限。 套接字本身将放置在 /run/uwsgi
目录中(稍后我们将创建此目录),uWSGI 和 Nginx 都可以访问它。 我们将设置 vacuum
选项,以便在服务停止时自动清理套接字文件:
[uwsgi] project = firstsite username = user base = /home/%(username) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application master = true processes = 5 uid = %(username) socket = /run/uwsgi/%(project).sock chown-socket = %(username):nginx 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
变量:
[uwsgi] project = firstsite username = user base = /home/%(username) chdir = %(base)/%(project) home = %(base)/Env/%(project) module = %(project).wsgi:application master = true processes = 5 uid = %(username) socket = /run/uwsgi/%(project).sock chown-socket = %(username):nginx chmod-socket = 660 vacuum = true
完成后保存并关闭文件。 您的第二个项目现在应该可以开始了。
为 uWSGI 创建一个 Systemd 单元文件
我们现在有了为 Django 项目提供服务所需的配置文件,但我们还没有自动化这个过程。 接下来,我们将创建一个 Systemd 单元文件以在启动时自动启动 uWSGI。
我们将在保存用户创建的单元文件的 /etc/systemd/system
目录中创建单元文件。 我们将调用我们的文件 uwsgi.service
:
sudo nano /etc/systemd/system/uwsgi.service
从 [Unit]
部分开始,该部分用于指定元数据。 我们将在这里简单地描述我们的服务:
[Unit] Description=uWSGI Emperor service
接下来,我们将打开 [Service]
部分。 我们将使用 ExecStartPre
指令来设置运行服务器所需的部分。 这将确保创建 /run/uwsgi
目录,并且我们的普通用户拥有它,并且 Nginx 组作为组所有者。 带有 -p
标志的 mkdir
和 chown
命令都成功返回,即使它们已经存在。 这就是我们想要的。
对于由 ExecStart
指令指定的实际启动命令,我们将指向 uwsgi
可执行文件。 我们将告诉它以“Emperor 模式”运行,允许它使用在 /etc/uwsgi/sites
中找到的文件来管理多个应用程序。 我们还将添加 Systemd 正确管理流程所需的部分。 这些取自uWSGI文档here:
[Unit] Description=uWSGI Emperor service [Service] ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi' ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all
现在,我们需要做的就是添加 [Install]
部分。 这允许我们指定何时应该自动启动服务。 我们将把我们的服务绑定到多用户系统状态。 每当系统为多个用户设置(正常运行条件)时,我们的服务将被激活:
[Unit] Description=uWSGI Emperor service [Service] ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi' ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all [Install] WantedBy=multi-user.target
完成此操作后,保存并关闭文件。
此时我们将无法成功启动服务,因为它依赖于可用的 nginx
用户。 我们将不得不等到安装 Nginx 之后才能启动 uWSGI 服务。
安装和配置 Nginx 作为反向代理
配置好 uWSGI 并准备就绪后,我们现在可以安装和配置 Nginx 作为我们的反向代理。 这可以使用 yum
下载和安装:
sudo yum install nginx
安装 Nginx 后,我们可以继续编辑主配置文件:
sudo nano /etc/nginx/nginx.conf
在此文件中,在现有服务器块旁边,我们将为每个站点创建一个附加服务器块:
http { . . . include /etc/nginx/conf.d/*.conf; server { } server { } server { listen 80 default_server; server_name localhost; . . .
我们创建的块将保存我们的 uWSGI 站点的配置。 我们现在将在第一个服务器块中介绍我们需要的指令。
首先,我们需要告诉服务器块它应该响应哪个端口号和域名。 我们假设您的每个站点都有一个域名:
server { listen 80; server_name firstsite.com www.firstsite.com; }
接下来,我们将告诉 Nginx,我们不需要担心丢失 favicon。 然后,我们将指定在请求这些文件时收集第一个站点的静态资产的目录。 Nginx 可以从该目录直接将它们交给客户端:
server { listen 80; server_name firstsite.com www.firstsite.com; location = favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/user/firstsite; } }
接下来,我们创建一个包罗万象的位置块,它将所有额外的查询直接传递给 uWSGI。 我们将包含 /etc/nginx/uwsgi_params
文件中的 uwsgi
参数,并将流量传递到 uWSGI 服务器设置的套接字:
server { listen 80; server_name firstsite.com www.firstsite.com; location = favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/user/firstsite; } location / { include uwsgi_params; uwsgi_pass unix:/run/uwsgi/firstsite.sock; } }
这样,我们的第一个服务器块就完成了。
我们其他站点的第二个服务器块将几乎相同。 您可以复制并粘贴我们刚刚创建的服务器块以开始使用。 您将需要修改站点应响应的域名、站点静态文件的位置以及站点的套接字文件:
server { listen 80; server_name secondsite.com www.secondsite.com; location = favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/user/secondsite; } location / { include uwsgi_params; uwsgi_pass unix:/run/uwsgi/secondsite.sock; } }
完成此步骤后,保存并关闭文件。
检查 Nginx 文件的语法以确保没有任何错误:
sudo nginx -t
如果没有错误报告,我们的文件状况良好。
我们还必须完成一项额外任务才能使我们的网站正常运行。 由于 Nginx 直接处理静态文件,它需要访问适当的目录。 我们需要为我们的主目录赋予它可执行权限,这是它唯一缺少的权限位。
最安全的方法是将 Nginx 用户添加到我们自己的用户组中。 然后,我们可以将可执行权限添加到主目录的组所有者,从而为 Nginx 提供足够的访问权限来提供文件:
sudo usermod -a -G user nginx chmod 710 /home/user
现在,我们可以启动 Nginx 服务器和 uWSGI 进程:
sudo systemctl start nginx sudo systemctl start uwsgi
您现在应该能够通过访问它们各自的域名来访问您的两个项目。 公共和管理界面都应该按预期工作。
如果一切顺利,您可以通过键入以下命令启用这两个服务在启动时自动启动:
sudo systemctl enable nginx sudo systemctl enable uwsgi
结论
在本指南中,我们设置了两个 Django 项目,每个项目都在自己的虚拟环境中。 我们已经将 uWSGI 配置为使用为每个项目配置的虚拟环境独立地为每个项目提供服务。 之后,我们设置 Nginx 作为反向代理来处理客户端连接并根据客户端请求为正确的项目提供服务。
Django 通过提供许多通用部分使创建项目和应用程序变得简单,让您可以专注于独特的元素。 通过利用本文中描述的通用工具链,您可以轻松地为您从单个服务器创建的应用程序提供服务。