如何在 Debian 8 上使用 uWSGI 和 Nginx 服务 Django 应用程序

介绍

Django 是一个强大的 Web 框架,可以帮助您将您的 Python 应用程序或网站从地面上获得。Django 包含一个简化开发服务器来本地测试您的代码,但对于任何与生产有关的内容,需要一个更安全、更强大的 Web 服务器。

在本指南中,我们将展示如何在 Debian 8 上安装和配置某些组件以支持和服务 Django 应用程序. 我们将配置 uWSGI 应用程序容器服务器以与我们的应用程序进行交互。

前提和目标

要完成本指南,你应该有一个新的 Debian 8 服务器实例,有一个非根用户,配置了sudo特权,你可以通过我们的 初始服务器设置指南来学习如何设置此设置。

我们将在两个不同的虚拟环境中安装Django,这将允许您的项目和他们的需求单独处理,我们将创建两个样本项目,以便在多项目环境中运行步骤。

一旦我们有我们的应用程序,我们将安装和配置 uWSGI 应用程序服务器. 这将作为我们的应用程序的接口,该接口将使用 HTTP 将客户端请求翻译成我们的应用程序可以处理的 Python 呼叫。

让我们开始吧。

安装和配置 VirtualEnv 和 VirtualEnvWrapper

为了做到这一点,我们将安装virtualenv,可以创建Python虚拟环境,以及virtualenvwrapper,为virtualenv工作流添加一些可用性改进。

我们将使用Python包管理器的pip来安装这两个组件,我们可以从Debian存储库中安装这个实用程序。

如果您正在使用 Python 2 构建 Django 项目,请输入:

1sudo apt-get update
2sudo apt-get install python-pip

如果您正在使用 Python 3,请键入:

1sudo apt-get update
2sudo apt-get install python3-pip

现在你已经安装了pip,我们可以在全球范围内安装virtualenvvirtualenvwrapper

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

1sudo pip install virtualenv virtualenvwrapper

如果您正在使用 Python 3,请键入:

1sudo pip3 install virtualenv virtualenvwrapper

随着这些组件的安装,我们现在可以配置我们的壳与它需要与virtualenvwrapper脚本工作的信息。 我们的虚拟环境将被放置在我们的主文件夹中的一个目录中,称为Env,以便轻松访问。

如果您正在使用 Python 3pip3命令,您还需要为您的壳初始化脚本添加一个额外的行:

1echo "export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3" >> ~/.bashrc

無論您正在使用哪個版本的 Python,您需要執行以下命令:

1echo "export WORKON_HOME=~/Env" >> ~/.bashrc
2echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc

现在,源您的壳初始化脚本,以便您可以在当前会话中使用此功能:

1source ~/.bashrc

您现在应该在您的主文件夹中有名为Env的目录,该目录将包含虚拟环境信息。

创建 Django 项目

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

创建第一个项目

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

创建您的第一个虚拟环境,键入您的第一个网站或项目的名称:

1mkvirtualenv firstsite

这将创建一个虚拟环境,在其内部安装Python和pip,并激活环境。您的提示将改变以表示您现在在新的虚拟环境中运作。它将看起来像这样的东西: (firstsite)user@hostname:~$. 窗口中的值是您的虚拟环境的名称。通过 pip安装的任何软件现在将安装在虚拟环境中,而不是在全球系统上。

我们的第一个步骤将是安装Django本身,我们可以用pip来做到这一点而不使用sudo,因为我们正在本地在我们的虚拟环境中安装它:

1pip install django

安装了 Django,我们可以通过键入创建我们的第一个样本项目:

1cd ~
2django-admin.py startproject firstsite

在您的主目录中,将创建一个名为firstsite的目录,其中有一个用于处理项目的不同方面的管理脚本,另一个名为firstsite的目录则用于容纳实际项目代码。

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

1cd ~/firstsite

首先,您可以迁移数据库以初始化我们项目将使用的 SQLite 数据库. 如果您想要,您可以为您的应用程序设置替代数据库,但这不在本指南的范围内:

1./manage.py migrate

您现在应该在项目目录中有名为「db.sqlite3」的数据库文件,现在我们可以通过键入:

1./manage.py createsuperuser

您将需要选择用户名,提供联系人电子邮件地址,然后选择并确认密码。

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

1nano ~/firstsite/firstsite/settings.py

首先,找出ALLOWED_HOSTS指令,定义一个地址白列表或域名可以用来连接到Django实例。任何未列入此列表的 Host标题的输入请求都会引发一个例外。

在方块中,列出与您的 Django 服务器相关的 IP 地址或域名。每个项目都应该列入引文中,其中有条纹分开的条目。如果您希望对整个域和任何子域的请求,请预先预设一个时间段,以便开始输入。在下面的片段中,有几个被评论的示例用于示范:

1[label ~/myproject/myproject/settings.py]
2. . .
3# The simplest case: just add the domain name(s) and IP addresses of your Django server
4# ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
5# To respond to 'example.com' and any subdomains, start the domain with a dot
6# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
7ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .]

由于我们将设置 Nginx 来服务我们的网站,我们需要配置一个目录,该目录将包含我们的网站的静态资产。这将允许 Nginx 直接服务这些资产,这将对性能产生积极的影响。我们会告诉 Django 将这些内容放入一个名为静态的目录,在我们的项目的基本目录中。

1[label ~/firstsite/firstsite/settings.py]
2. . .
3STATIC_URL = '/static/'
4STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

当你完成时,保存并关闭文件. 现在,收集我们的站点的静态元素,并通过键入将其放入该目录中:

1./manage.py collectstatic

您可以输入来确认操作并收集静态内容. 您的项目目录中将有一个名为静态的新目录。

您可能需要调整防火墙设置以允许流量到我们的Django开发服务器,我们将在端口8080上运行。

如果您正在运行ufw防火墙,您可以通过键入以下方式允许流量到端口 8080:

1sudo ufw allow 8080

如果您正在运行iptables,则所需的准确命令取决于当前的防火墙配置。

1sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT

有了这一切,我们可以通过暂时启动开发服务器来测试我们的项目。

1./manage.py runserver 0.0.0.0:8080

这将启动开发服务器在端口 8080. 访问您的服务器的域名或 IP 地址,其次是 8080 在您的浏览器:

1http://server_domain_or_IP:8080

你应该看到一个看起来像这样的页面:

Django sample site

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

Django admin login

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

Django admin interface

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

创建第二个项目

第二个项目将以与前一个完全相同的方式创建,我们将在本节中补充解释,看你已经完成了这个过程。

回到您的主目录并为您的新项目创建第二个虚拟环境。

1cd ~
2mkvirtualenv secondsite
3pip install django

新的环境将被创建 and 更改,留下你的以前的虚拟环境. 这个 Django 实例完全与您配置的另一个完全分开。

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

1django-admin.py startproject secondsite
2cd ~/secondsite

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

1./manage.py migrate
2./manage.py createsuperuser

打开设置文件:

1nano ~/secondsite/secondsite/settings.py

ALLOWED_HOSTS设置为您第二个项目的域名、服务器的IP地址或两者,就像您在第一个项目中一样:

1ALLOWED_HOSTS = ['second_project_domain_or_IP', 'another_domain_or_IP', . . .]

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

1[label ~/secondsite/secondsite/settings.py]
2. . .
3STATIC_URL = '/static/'
4STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

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

1./manage.py collectstatic

最后,打开开发服务器来测试网站:

1./manage.py runserver 0.0.0.0:8080

您应该检查常规网站在:

1http://server_domain_or_IP:8080

此外,您还可以登录 admin 网站:

1http://server_domain_or_IP:8080/admin

当您确认一切按预期运行时,请在终端中键入 CTRL-C 以停止开发服务器。

退出虚拟环境

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

1deactivate

如果您需要在任何一个 Django 站点上再次工作,您应该重新激活相应的环境,您可以使用workon命令做到这一点:

1workon firstsite

或:

1workon secondsite

再次,在您完成在您的网站上工作时禁用:

1deactivate

安装 uWSGI 应用服务器

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

安装UWSGI

与上面链接的指南不同,在本教程中,我们将安装uWSGI在全球范围内,这将减少处理多个Django项目的摩擦。在我们安装uWSGI之前,我们需要软件依赖的Python开发文件。

如果您正在使用 Django 與 Python 2,請輸入:

1sudo apt-get install python-dev

如果您正在使用 Python 3,请键入:

1sudo apt-get install python3-dev

现在开发文件已经可用,我们可以通过pip在全球范围内安装 uWSGI。

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

1sudo pip install uwsgi

如果您正在使用 Python 3,请键入:

1sudo pip3 install uwsgi

我們可以快速測試這個應用程式伺服器,通過傳遞給它我們的網站之一的信息,例如,我們可以告訴它服務我們的第一個項目,通過輸入:

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

在这里,我们告诉uWSGI使用我们位于我们的~/Env目录中的虚拟环境,更改到我们的项目目录,并使用我们内部firstsite目录中存储的wsgi.py文件来服务该文件. 为了我们的演示,我们告诉它在端口8080上服务HTTP。 如果您在浏览器中访问服务器的域名或IP地址,然后是:8080,您将再次看到您的网站(CSS等/admin界面中的静态元素还不会起作用)。

创建配置文件

从命令行运行 uWSGI 对测试有用,但对于实际部署并不特别有用,相反,我们将在皇帝模式中运行 uWSGI,这允许主流程自动管理单独的应用程序,因为有一组配置文件。

创建一个存储您的配置文件的目录. 由于这是一个全球性的过程,我们将创建一个名为 `/etc/uwsgi/sites’ 的目录来存储我们的配置文件。

1sudo mkdir -p /etc/uwsgi/sites
2cd /etc/uwsgi/sites

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

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

1sudo nano firstsite.ini

内部,我们必须从[uwsgi]部分标题开始。我们所有的信息都会在这个标题下进行。我们还将使用变量来使我们的配置文件更加可重复使用。标题后,设置一个名为项目的变量,以你的第一个项目的名称。添加一个名为uid的变量,其中包含你的sudo用户名。

我们还将添加一个名为base的变量,并将路径添加到您的用户主目录中。这将是我们使用%(variable_name)语法设置的用户名构建的。

1[label /etc/uwsgi/sites/firstsite.ini]
2[uwsgi]
3project = firstsite
4uid = sammy
5base = /home/%(uid)

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

通过设置模块,我们可以准确地说明如何与我们的项目进行交互(通过从我们项目目录中的 wsgi.py 文件中导入可调用的应用程序)。

 1[label /etc/uwsgi/sites/firstsite.ini]
 2[uwsgi]
 3project = firstsite
 4uid = sammy
 5base = /home/%(uid)
 6
 7# Next, add the lines below
 8chdir = %(base)/%(project)
 9home = %(base)/Env/%(project)
10module = %(project).wsgi:application

我们想创建一个5名工人的主流程,我们可以通过添加以下内容来完成:

 1[label /etc/uwsgi/sites/firstsite.ini]
 2[uwsgi]
 3project = firstsite
 4uid = sammy
 5base = /home/%(uid)
 6
 7chdir = %(base)/%(project)
 8home = %(base)/Env/%(project)
 9module = %(project).wsgi:application
10
11# Next, add these lines
12master = true
13processes = 5

接下来,我们需要指定 uWSGI 应该如何倾听连接. 在我们的 uWSGI 测试中,我们使用了 HTTP 和网络端口. 然而,由于我们将使用 Nginx 作为反向代理,我们有更好的选择。

由于所有组件都在单一服务器上运行,我们可以使用Unix接口,而不是使用网络端口,这更安全,提供更好的性能。这个接口不会使用HTTP,而是将实施uWSGI的uwsgi协议,这是一个快速的二进制协议,用于与其他服务器进行通信。

我们还会修改插件的所有权和权限,因为我们会给网页服务器写入访问权限,我们会设置真空选项,以便在停止服务时自动清除插件文件:

 1[label /etc/uwsgi/sites/firstsite.ini]
 2[uwsgi]
 3project = firstsite
 4uid = sammy
 5base = /home/%(uid)
 6
 7chdir = %(base)/%(project)
 8home = %(base)/Env/%(project)
 9module = %(project).wsgi:application
10
11master = true
12processes = 5
13
14# Finish off the configuration with the following lines
15socket = /run/uwsgi/%(project).sock
16chown-socket = %(uid):www-data
17chmod-socket = 660
18vacuum = true

这样,我们的第一个项目的 uWSGI 配置就完成了. 保存并关闭文件。

使用变量设置文件的优点是,它使其非常容易重复使用. 复制您的第一个项目的配置文件以作为您的第二个配置文件的基础:

1sudo cp /etc/uwsgi/sites/firstsite.ini /etc/uwsgi/sites/secondsite.ini

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

1sudo nano /etc/uwsgi/sites/secondsite.ini

我们只需要在该文件中更改一个值,以便为我们的第二个项目工作。

 1[label /etc/uwsgi/sites/secondsite.ini]
 2[uwsgi]
 3project = secondsite
 4uid = sammy
 5base = /home/%(uid)
 6
 7chdir = %(base)/%(project)
 8home = %(base)/Env/%(project)
 9module = %(project).wsgi:application
10
11master = true
12processes = 5
13
14socket = /run/uwsgi/%(project).sock
15chown-socket = %(uid):www-data
16chmod-socket = 660
17vacuum = true

保存并关闭文件完成后. 您的第二个项目应该准备好现在。

创建 uWSGI 的 systemd 单元文件

我们现在有配置文件,我们需要为我们的Django项目服务,但我们还没有自动化这个过程。

我们将创建单元文件在 /etc/systemd/system 目录中,在那里存储用户创建的单元文件. 我们将我们的文件称为 uwsgi.service:

1sudo nano /etc/systemd/system/uwsgi.service

[单位]部分开始,用于指定元数据和订购信息,我们将简单地在这里列出我们的服务的描述:

1[label /etc/systemd/system/uwsgi.service]
2[Unit]
3Description=uWSGI Emperor service

接下来,我们将打开[服务]部分。我们将使用ExecStartPre指令来设置我们需要运行我们的服务器的零件。这将确保创建了/run/uwsgi目录,我们的正常用户将其拥有与www-data组作为组所有者。

对于ExecStart指令规定的实际启动命令,我们会指向uwsgi可执行的命令,我们会告诉它在Emperor模式下运行,允许它使用它在/etc/uwsgi/sites中找到的文件来管理多个应用程序。

 1[label /etc/systemd/system/uwsgi.service]
 2[Unit]
 3Description=uWSGI Emperor service
 4
 5[Service]
 6ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi'
 7ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
 8Restart=always
 9KillSignal=SIGQUIT
10Type=notify
11NotifyAccess=all

现在,我们所需要做的只是添加[安装]部分,这使我们能够指定服务何时自动启动,我们将我们的服务与多用户系统状态相关联,每次系统设置为多用户(正常操作状态),我们的服务将被激活:

 1[label /etc/systemd/system/uwsgi.service]
 2[Unit]
 3Description=uWSGI Emperor service
 4
 5[Service]
 6ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown sammy:www-data /run/uwsgi'
 7ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
 8Restart=always
 9KillSignal=SIGQUIT
10Type=notify
11NotifyAccess=all
12
13[Install]
14WantedBy=multi-user.target

完成后,保存并关闭文件。

我们将无法在此时成功启动服务,因为它依赖于www-data用户的可用性,我们将不得不等待在安装 Nginx 后启动 uWSGI 服务。

安装和配置 Nginx 作为反向代理

有了 uWSGI 配置并做好准备,我们现在可以安装和配置 Nginx 作为我们的反向代理程序。

1sudo apt-get install nginx

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

1sudo nano /etc/nginx/sites-available/firstsite

内部,我们可以通过指明我们的第一个项目应该可访问的端口号和域名来启动我们的服务器块。

1[label /etc/nginx/sites-available/firstsite]
2server {
3    listen 80;
4    server_name firstsite.com www.firstsite.com;
5}

接下来,我们可以告诉 Nginx 忽略错误,如果找不到 favicon,我们还会将其指向我们收集网站的静态元素的静态文件目录的位置:

 1[label /etc/nginx/sites-available/firstsite]
 2server {
 3    listen 80;
 4    server_name firstsite.com www.firstsite.com;
 5
 6    location = /favicon.ico { access_log off; log_not_found off; }
 7    location /static/ {
 8        root /home/sammy/firstsite;
 9    }
10}

接下来,我们可以创建一个 catch-all 位置块,将所有额外的查询直接传递到我们的应用程序中,我们将包括在 /etc/nginx/uwsgi_params 中发现的 uwsgi` 参数,并将流量传输到 uWSGI 服务器设置的接口:

 1[label /etc/nginx/sites-available/firstsite]
 2server {
 3    listen 80;
 4    server_name firstsite.com www.firstsite.com;
 5
 6    location = /favicon.ico { access_log off; log_not_found off; }
 7    location /static/ {
 8        root /home/sammy/firstsite;
 9    }
10
11    location / {
12        include uwsgi_params;
13        uwsgi_pass unix:/run/uwsgi/firstsite.sock;
14    }
15}

有了这个,我们的第一个服务器块完成了,您可以保存和退出文件。

我们将用此作为我们第二个项目的 Nginx 配置文件的基础。

1sudo cp /etc/nginx/sites-available/firstsite /etc/nginx/sites-available/secondsite

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

1sudo nano /etc/nginx/sites-available/secondsite

在这里,您将不得不将任何firstsite的引用更改为secondsite。您还需要更改server_name,以便您的第二个项目响应不同的域名。

 1[label /etc/nginx/sites-available/secondsite]
 2server {
 3    listen 80;
 4    server_name secondsite.com www.secondsite.com;
 5
 6    location = /favicon.ico { access_log off; log_not_found off; }
 7    location /static/ {
 8        root /home/sammy/secondsite;
 9    }
10
11    location / {
12        include uwsgi_params;
13        uwsgi_pass unix:/run/uwsgi/secondsite.sock;
14    }
15}

保存并关闭文件,当你完成。

接下来,将您的两个新配置文件链接到 Nginx 的网站启用目录,以启用它们:

1sudo ln -s /etc/nginx/sites-available/firstsite /etc/nginx/sites-enabled
2sudo ln -s /etc/nginx/sites-available/secondsite /etc/nginx/sites-enabled

通过键入检查配置语法:

1sudo nginx -t
1nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
2nginx: configuration file /etc/nginx/nginx.conf test is successful

如果没有发现语法错误,您可以重新启动您的 Nginx 服务来加载新的配置:

1sudo systemctl restart nginx

如果你记得从以前,我们从来没有真正启动uWSGI服务器。

1sudo systemctl start uwsgi

我们需要重新通过我们的防火墙进行调整,我们不再需要打开端口8080,因为我们正在通过Nginx代理,所以我们可以删除这个规则,然后我们可以添加一个例外来允许流量到 Nginx过程。

如果你正在使用ufw,你可以通过键入这样做:

1sudo ufw delete allow 8080
2sudo ufw allow 'Nginx Full'

如果您使用iptables,相应的命令将看起来像这样:

1sudo iptables -D INPUT -p tcp --dport 8080 -j ACCEPT
2sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT

您现在应该能够通过前往各自的域名来接触您的两个项目,公共和行政界面都应该按照预期工作。

如果情况顺利,您可以通过键入两个服务在启动时自动启动:

1sudo systemctl enable nginx
2sudo systemctl enable uwsgi

<$>[注] [标签注] 配置 Nginx 后,下一步应该是使用 SSL/TLS 来确保服务器的流量。

如果您有域名,获取 SSL 证书以保护您的流量最简单的方法是使用 Let's Encrypt。

如果您没有域名,您仍然可以使用自签名的SSL证书(https://andsky.com/tech/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-debian-8)来保护您的网站进行测试和学习。

结论

在本指南中,我们已经设置了两个Django项目,每个在自己的虚拟环境中。我们已经配置了uWSGI来独立使用每个项目配置的虚拟环境来服务每个项目。

Django 通过提供许多常见元素来简化项目和应用程序的创建,使您能够专注于独特的元素,通过利用本文中描述的通用工具链,您可以轻松地从单一服务器中服务您创建的应用程序。

Published At
Categories with 技术
comments powered by Disqus