如何在Debian 8上使用uWSGI和Nginx配置Django应用程序

Django是一个强大的网络框架,可以帮助你让你的Python应用程序或网站离地面。 Django包括一个简化的开发服务器,用于在本地测试代码,但对于任何与生产相关的任何事情,一个更安全和强大的Web服务器...

介绍

Django是一个强大的网络框架,可以帮助你让你的Python应用程序或网站离地面。 Django包括一个用于在本地测试代码的简化开发服务器,但是对于与生产有关的任何事情,需要一个更安全和更强大的Web服务器。 在本指南中,我们将演示如何在Debian 8上安装和配置一些组件,以支持和提供Django应用程序。我们将配置uWSGI应用程序容器服务器以与我们的应用程序接口。然后我们将设置Nginx反向代理uWSGI,让我们访问其安全和性能功能来服务我们的应用程序。

先决条件和目标

为了完成这个指南,你应该有一个非root用户耳目一新的Debian 8服务器实例sudo配置权限。 你可以学习如何通过我们的运行设置此服务器初始设置指南 。 我们将在两个不同的虚拟环境中安装Django。这将允许您的项目及其需求单独处理。我们将创建两个示例项目,以便我们可以在多项目环境中运行这些步骤。 一旦我们有应用程序,我们将安装和配置uWSGI应用程序服务器。这将作为我们的应用程序的接口,它将客户端请求使用HTTP转换为我们的应用程序可以处理的Python调用。然后,我们将在uWSGI之前设置Nginx,以利用其高性能连接处理机制和易于实现的安全特性。 让我们开始吧。

安装和配置VirtualEnv和VirtualEnvWrapper

我们将在自己的虚拟环境中安装我们的Django项目,以隔离每个项目的需求。要做到这一点,我们就可以安装virtualenv ,它可以创造Python的虚拟环境,并virtualenvwrapper ,它增加了一些实用性改进了virtualenv工作流程。 我们将同时安装使用这些组件的pip ,Python的包管理器。我们可以从Debian仓库安装这个实用程序。 如果您在使用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安装,我们可以安装virtualenvvirtualenvwrapper全球。 如果您正在使用Python 2,请键入:
sudo pip install virtualenv virtualenvwrapper
如果您正在使用Python 3,键入:
sudo pip3 install virtualenv virtualenvwrapper
安装这些组件,现在我们可以用它需要与合作的信息来配置我们的外壳virtualenvwrapper脚本。 我们的虚拟环境都将在我们称为home文件夹放在一个目录内的Env以方便访问。 这是通过一个叫做环境变量配置WORKON_HOME 。我们可以将其添加到我们的shell初始化脚本中,并且可以获取虚拟环境包装器脚本。 如果您正在使用Python 3pip3命令,你将有一个额外的行添加到您的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本身。我们可以使用pip这个没有sudo ,因为我们在我们的虚拟环境中进行本地安装这样的:
pip install django
安装Django后,我们可以通过键入以下内容创建我们的第一个示例项目:
cd ~
django-admin.py startproject firstsite
这将创建一个名为firstsite你的home目录中。这是一个用于处理项目各个方面的管理脚本和用于容纳实际项目代码的同名的另一个目录。 移动到第一级目录,以便我们可以开始设置我们的示例项目的最低要求。
cd ~/firstsite
首先迁移数据库以初始化我们的项目将使用的SQLite数据库。如果您愿意,可以为应用程序设置备用数据库,但这不在本指南的范围之内:
./manage.py migrate
您现在应该有一个名为数据库文件db.sqlite3在项目目录。现在,我们可以通过键入以下内容创建管理用户:
./manage.py createsuperuser
您必须选择用户名,提供联系人电子邮件地址,然后选择并确认密码。 接下来,使用文本编辑器打开项目的设置文件:
nano ~/firstsite/firstsite/settings.py
通过查找开始ALLOWED_HOSTS指令。 这定义了地址或域名的白名单可用于连接到Django实例。 任何传入的请求与主机头不在此名单将引发异常。 Django要求您设置此项以防止某类安全漏洞。 在方括号中,列出与您的Django服务器相关联的IP地址或域名。每个项目都应在引号中列出,条目用逗号分隔。如果您希望请求整个域和任何子域,请在该条目的开头添加一个句点。在下面的代码段中,有几个注释掉的示例用于演示:
〜/ myproject / myproject / 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/')
保存并在完成后关闭文件。现在,收集我们网站的静态元素,并通过键入以下内容将其放在该目录中:
./manage.py collectstatic
您可以键入“是”以确认操作并收集静态内容。将有一个名为新目录static在您的项目目录。 您可能必须调整防火墙设置,以允许流量到我们的Django开发服务器,我们将在端口8080上运行。 如果你正在运行一个ufw防火墙,您可以通过键入允许通信端口8080:
sudo ufw allow 8080
如果您正在运行iptables相反,你需要确切的命令取决于您当前的防火墙配置。 对于大多数配置 ,这个命令应该工作:
sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
有了这一切,我们可以通过临时启动开发服务器来测试我们的项目。要启动开发服务器,请键入:
./manage.py runserver 0.0.0.0:8080
这将在端口启动开发服务器8080 。 访问您的服务器的域名或IP地址,随后8080在浏览器中:
http://server_domain_or_IP:8080
您应该看到如下所示的页面: Django示例网站 添加/admin在浏览器的地址栏中的URL的末尾,你会被带到管理员登录页面: Django管理员登录 使用你所选择的管理登录凭据createsuperuser命令,登录到服务器。然后,您将可以访问管理界面: Django管理界面 测试此功能后,通过在终端中键入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/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/')
保存并关闭文件。现在,通过键入以下内容将静态元素收集到该目录中:
./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的标准接口与应用程序通信。要了解更多关于这一点,阅读这部分我们的指南有关建立uWSGI和Nginx的在Ubuntu 14.04。

安装uWSGI

与上面链接的指南不同,在本教程中,我们将在全球安装uWSGI。这将在处理多个Django项目时创建较少的摩擦。在我们可以安装uWSGI之前,我们需要软件依赖的Python开发文件。我们可以直接从Debian的存储库安装。 如果你一直使用Django和Python 2,请键入:
sudo apt-get install python-dev
如果你已经使用Python 3,键入:
sudo apt-get install python3-dev
现在,发展的文件都可以,我们可以通过安装在全球uWSGI pip 。 如果您正在使用Python 2,请键入:
sudo pip install uwsgi
如果您正在使用Python 3,键入:
sudo pip3 install uwsgi
我们可以通过传递其中一个站点的信息来快速测试此应用程序服务器。例如,我们可以通过键入以下内容来告诉它服务我们的第一个项目:
uwsgi --http :8080 --home /home/sammy/Env/firstsite --chdir /home/sammy/firstsite -w firstsite.wsgi
在这里,我们已经告诉uWSGI使用我们位于我们的虚拟环境的~/Env目录,改变我们项目的目录,并使用wsgi.py存储在我们内心中的文件firstsite目录服务文件。 对于我们的演示,我们告诉它要服务于HTTP端口8080 。 如果你到服务器的域名,或在浏览器中,然后通过IP地址:8080 ,你将再次看到你的网站(静态元素在/admin界面,如CSS,将无法工作)。当您完成测试此功能时,在终端中键入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与第一个项目的名称。 添加一个变量,名为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)

# Next, add the lines below
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

# Next, add these lines
master = true
processes = 5
接下来,我们需要指定uWSGI应该如何监听连接。在我们的uWSGI测试中,我们使用HTTP和网络端口。但是,由于我们将使用Nginx作为反向代理,我们有更好的选择。 而不是使用网络端口,因为所有组件都在单个服务器上运行,我们可以使用Unix套接字。这更安全,并提供更好的性能。这种socket将不会使用HTTP,而是将实施uWSGI的uwsgi协议,它是一种快速二进制协议被设计用于与其他服务器进行通信。 Nginx的可以本地代理使用uwsgi协议,所以这是我们最好的选择。 我们还将修改套接字的所有权和权限,因为我们将给予Web服务器写访问权限。我们将设置vacuum ,以便socket文件将在该服务停止时自动清理选项:
/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

# Finish off the configuration with the following lines
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。 我们将在创建单元文件/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组作为组所有者。 两者mkdir-p标志和chown命令返回成功,即使没有需要他们的操作。这是我们想要的。 对于实际的启动命令,由指定的ExecStart指令,我们将指向uwsgi可执行文件。 我们会告诉它以“皇帝模式”下运行,使其能够管理多个应用程序中使用它找到的文件/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的用户是可用的。我们将不得不等待启动uWSGI服务,直到Nginx安装后。

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

通过配置uWSGI并准备好,我们现在可以安装和配置Nginx作为我们的反向代理。这可以从Debian的默认存储库下载:
sudo apt-get install nginx
一旦Nginx安装,我们可以为每个项目创建一个服务器块配置文件。从第一个项目开始,通过创建服务器块配置文件:
sudo nano /etc/nginx/sites-available/firstsite
在里面,我们可以通过指示我们的第一个项目应该可访问的端口号和域名来启动我们的服务器块。我们假设您有一个域名:
/ etc / nginx / sites-available / firstsite
server {
    listen 80;
    server_name firstsite.com www.firstsite.com;
}
接下来,如果找不到favicon,我们可以告诉Nginx忽略错误。我们还将它指向我们的静态文件目录的位置,我们收集我们的网站的静态元素:
/ 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;
    }
}
接下来,我们可以创建一个捕获位置块,将所有其他查询直接传递到我们的应用程序。我们将包括uwsgi在发现参数/etc/nginx/uwsgi_params并通过流量的uWSGI服务器设置了socket:
/ 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 ,以便您的第二个项目是为了响应不同的域名。当你完成后,它将看起来像这样:
/ 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: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
如果未检测到语法错误,您可以重新启动Nginx服务以加载新配置:
sudo systemctl restart nginx
如果你记得早些时候,我们从来没有真正启动uWSGI服务器。现在通过键入:
sudo systemctl start uwsgi
我们需要再次调整防火墙。我们不再需要端口8080打开,因为我们代理通过Nginx,所以我们可以删除该规则。然后我们可以添加一个异常,以允许流量到Nginx进程。 如果你正在使用ufw ,您可以通过键入做到这一点:
sudo ufw delete allow 8080
sudo ufw allow 'Nginx Full'
如果您在使用iptables ,适当的命令会是这个样子:
sudo iptables -D INPUT -p tcp --dport 8080 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
现在您应该可以访问他们各自的域名访问您的两个项目。公共和管理接口都应按预期工作。 如果这样做顺利,您可以通过键入以下命令,使这两个服务在启动时自动启动:
sudo systemctl enable nginx
sudo systemctl enable uwsgi
注意
配置Nginx后,下一步应该是使用SSL / TLS确保流量到服务器。这很重要,因为没有它,所有信息,包括密码都通过网络以纯文本发送。 如果您有域名,获取SSL证书以确保流量的最简单方法是使用Let's Encrypt。按照本指南设置让我们Nginx的加密Debian 8 。 如果你没有一个域名,你仍然可以保证站点的安全测试,并与学习的自签名的SSL证书

结论

在本指南中,我们设置了两个Django项目,每个项目都在自己的虚拟环境中。我们已配置uWSGI使用为每个项目配置的虚拟环境独立服务每个项目。之后,我们设置Nginx作为反向代理来处理客户端连接,并根据客户端请求提供正确的项目。 Django通过提供许多常用的部分来简化创建项目和应用程序,使您能够专注于独特的元素。通过利用本文中描述的通用工具链,您可以轻松地从单个服务器提供您创建的应用程序。