Django是一个功能强大的Web框架,可以帮助您实现Python应用程序或网站。Django包含一个简化的开发服务器,用于在本地测试您的代码,但是对于任何与生产相关的细节,都需要一个更安全,更强大的Web服务器。
在本教程中,我们将演示如何在Debian 8上安装和配置某些组件以支持和服务Django应用程序。我们将配置uWSGI应用程序容器服务器以与我们的应用程序进行交互。然后,我们将设置Nginx以反向代理到uWSGI,使我们能够访问其安全性和性能功能来为我们的应用程序提供服务。
如果您使用CentOS系统,可以参考CentOS 7如何设置uWSGI和Nginx提供Python应用服务的这篇文章的教程。
在开始之前,您应该拥有一个在root用户服务器上可以使用sudo
命令权限的非root用户。没有服务器的同学可以在这里购买。
我们将在两个不同的虚拟环境中安装Django。我们将创建两个示例项目,以便我们可以在多项目环境中执行这些步骤。获得应用程序后,我们将安装和配置uWSGI应用程序服务器。这将作为我们的应用程序的接口,它将使用HTTP将客户端请求转换为我们的应用程序可以处理的Python调用。然后,我们将在uWSGI前面设置Nginx,以利用其高性能连接处理机制及其易于实现的安全功能。
我们将在虚拟环境中安装我们的Django项目,以隔离每个项目的需求。为此,我们将进行安装virtualenv
,这可以创建Python虚拟环境,并且virtualenvwrapper
可以为virtualenv
工作流程增加一些可用性改进。
我们将使用Python包管理器pip安装这两个组件。我们可以从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,我们可以在全球范围内安装virtualenv
和virtualenvwrapper
。
如果您使用的是Python 2,请输入:
$ sudo pip install virtualenv virtualenvwrapper
如果您使用的是Python 3,请输入:
$ sudo 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,并启动两个项目。
我们可以使用virtualenvwrapper
脚本提供给我们的一些命令轻松创建虚拟环境。
输入以下内容,使用您的第一个站点或项目的名称创建您的第一个虚拟环境:
$ mkvirtualenv firstsite
这将创建一个虚拟环境,在其中安装Python和pip,并激活环境。您的提示将更改为表示您现在正在新的虚拟环境中运行。它看起来像这样:(firstsite)user@hostname:~$
。括号中的值是虚拟环境的名称。通过pip安装的任何软件现在都将安装到虚拟环境中,而不是安装在全局系统上。
这允许我们在每个项目的基础上隔离我们的包。
我们的第一步是安装Django本身。我们可以在没有sudo
的情况下使用pip,因为我们在虚拟环境中本地安装它:
(firstsite) $ pip install django
安装Django后,我们可以通过输入以下内容来创建第一个示例项目:
(firstsite) $ cd ~
(firstsite) $ django-admin.py startproject firstsite
这将在您的主目录中创建一个名为firstsite
的目录。其中包括用于处理项目各个方面的管理脚本以及用于存放实际项目代码的另一个同名目录。
进入第一级目录,以便我们可以开始为示例项目设置最低要求。
(firstsite) $ cd ~/firstsite
首先迁移数据库以初始化我们的项目将使用的SQLite数据库。如果您愿意,可以为应用程序设置备用数据库,但这超出了本教程的范围:
(firstsite) $ ./manage.py migrate
您现在应该在项目目录中有一个名为db.sqlite3
的数据库文件。
现在,我们可以通过输入以下内容来创建管理用户
(firstsite) $ ./manage.py createsuperuser
您必须选择用户名,提供联系人电子邮件地址,然后选择并确认密码。
接下来,使用文本编辑器打开项目的设置文件:
(firstsite) $ 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/')
完成后保存并关闭文件。现在,收集我们网站的静态元素,并输入以下内容将它们放在该目录中:
(firstsite) $ ./manage.py collectstatic
您可以输入“是”以确认操作并收集静态内容。项目目录中将有一个名为static
的新目录。
您可能必须调整防火墙设置以允许流量到我们的Django开发服务器,我们将在端口8080上运行。
如果您正在运行ufw
防火墙,则可以通过输入以下内容来允许流量到端口8080:
myprojectenv) $ sudo ufw allow 8080
如果您正在运行iptables
,则所需的确切命令取决于您当前的防火墙配置。对于大多数配置,此命令应该起作用:
(myprojectenv) $ sudo iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
完成所有这些后,我们可以通过临时启动开发服务器来测试我们的项目。要启动开发服务器,请输入:
(firstsite) $ ./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实例完全独立于您配置的另一个实例。这允许您独立管理它们并根据需要进行自定义。
创建第二个项目并进入项目目录:
(secondsite) $ django-admin.py startproject secondsite
(secondsite) $ cd ~/secondsite
初始化数据库并创建管理用户:
(secondsite) $ ./manage.py migrate
(secondsite) $ ./manage.py createsuperuser
打开设置文件:
(secondsite) $ 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部分,我们可以停用我们的第二个虚拟环境:
(secondsite) $ deactivate
如果您需要再次使用任何一个Django站点,则应重新激活其各自的环境。您可以使用workon命令执行此操作:
$ workon firstsite
或者:
$ workon secondsite
在您完成网站工作后再次停用:
$ deactivate
现在我们已经准备好了两个Django项目,我们可以配置uWSGI。uWSGI是一个应用程序服务器,可以通过名为WSGI的标准接口与应用程序进行通信。
在本教程中,我们将全局安装uWSGI。这将减少处理多个Django项目的摩擦。在我们安装uWSGI之前,我们需要软件所依赖的Python开发文件。我们可以直接从Debian的存储库安装它。
如果您在Python 2中使用Django ,请输入:
$ sudo apt-get install python-dev
如果您一直在使用Python 3,请输入:
$ sudo apt-get install python3-dev
现在开发文件可用,我们可以通过pip
全局安装uWSGI 。
如果您使用的是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
目录中的虚拟环境,更改到我们项目的目录,并使用存储在我们内部firstsite
目录中的wsgi.py
文件来提供文件。对于我们的演示,我们告诉它在端口8080
上提供HTTP服务。如果您在浏览器访问服务器的域名或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
文件中导入可调用的“application”)。这些项的配置如下所示:
/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个workers的主进程。我们可以通过添加以下内容来实现:
/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,而不是使用网络端口。这更安全,性能更好。这个socket不会使用HTTP,而是实现uWSGI的uwsgi协议,这是一个快速的二进制协议,用于与其他服务器通信。Nginx可以使用uwsgi协议进行本机代理,因此这是我们的最佳选择。
我们还将修改socket的所有权和权限,因为我们将为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
完成后保存并关闭文件。你的第二个项目现在应该准备好了。
我们现在有了为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
组作为组所有者。即使不需要操作,带有-p
标志的mkdir
和chown
命令也会成功返回。
对于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服务。
随着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;
}
}
接下来,我们可以创建一个catch-all位置块,将所有其他查询直接传递给我们的应用程序。我们将包含/etc/nginx /uwsgi_params
中的uwsgi
参数,并将流量传递给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证书服务,它提供免费的可信证书。腾讯云SSL证书安装操作指南进行设置。
在本教程中,我们设置了两个Django项目,每个项目都在自己的虚拟环境中。我们已将uWSGI配置为使用为每个项目配置的虚拟环境独立地为每个项目提供服务。之后,我们设置Nginx作为反向代理来处理客户端连接并根据客户端请求提供正确的项目。
Django通过提供许多常见的部分使创建项目和应用程序变得简单,使您可以专注于独特的元素。
参考文献:《How To Serve Django Applications with uWSGI and Nginx on Debian 8》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。