如何在Debian8上使用Postgres、Nginx和Gunicorn设置Django
介绍
Django 是一个强大的 Web 框架,可以帮助您启动 Python 应用程序或网站。 Django 包含一个简化的开发服务器,用于在本地测试您的代码,但对于任何与生产相关的事情,都需要一个更安全、更强大的 Web 服务器。
在本指南中,我们将演示如何在 Debian 8 上安装和配置一些组件以支持和服务 Django 应用程序。 我们将设置一个 PostgreSQL 数据库,而不是使用默认的 SQLite 数据库。 我们将配置 Gunicorn 应用程序服务器以与我们的应用程序交互。 然后,我们将设置 Nginx 以反向代理 Gunicorn,使我们能够访问其安全性和性能特性来为我们的应用程序提供服务。
先决条件和目标
为了完成本指南,您应该拥有一个全新的 Debian 8 服务器实例,该实例具有配置了 sudo
权限的非 root 用户。 您可以通过我们的 初始服务器设置指南 来了解如何设置它。
我们将在虚拟环境中安装 Django。 将 Django 安装到特定于您的项目的环境中将允许单独处理您的项目及其要求。
一旦我们的数据库和应用程序启动并运行,我们将安装和配置 Gunicorn 应用程序服务器。 这将作为我们应用程序的接口,将 HTTP 中的客户端请求转换为我们的应用程序可以处理的 Python 调用。 然后我们将在 Gunicorn 前面设置 Nginx,以利用其高性能的连接处理机制和易于实现的安全特性。
让我们开始吧。
从 Debian 存储库安装软件包
要开始这个过程,我们将从 Debian 存储库下载并安装我们需要的所有项目。 稍后我们将使用 Python 包管理器 pip
安装其他组件。
我们需要更新本地的 apt
包索引,然后下载并安装包。 我们安装的包取决于您的项目将使用哪个版本的 Python。
如果您使用 Python 2,请键入:
sudo apt-get update sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx
如果您使用的是 Python 3,请键入:
sudo apt-get update sudo apt-get install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx
这将安装 pip
、稍后构建 Gunicorn 所需的 Python 开发文件、Postgres 数据库系统和与之交互所需的库,以及 Nginx Web 服务器。
创建 PostgreSQL 数据库和用户
我们将直接进入并为我们的 Django 应用程序创建一个数据库和数据库用户。
默认情况下,Postgres 使用称为“对等身份验证”的身份验证方案进行本地连接。 基本上,这意味着如果用户的操作系统用户名与有效的 Postgres 用户名匹配,则该用户无需进一步身份验证即可登录。
在 Postgres 安装期间,创建了一个名为 postgres
的操作系统用户,以对应于 postgres
PostgreSQL 管理用户。 我们需要使用这个用户来执行管理任务。 我们可以使用 sudo 并通过 -u
选项传入用户名。
通过键入以下内容登录到交互式 Postgres 会话:
sudo -u postgres psql
您将收到一个 PostgreSQL 提示,我们可以在其中设置我们的要求。
首先,为您的项目创建一个数据库:
笔记
每个 Postgres 语句都必须以分号结尾,因此请确保您的命令以一个结尾以避免出现问题。
CREATE DATABASE myproject;
OutputCREATE DATABASE
接下来,为我们的项目创建一个数据库用户。 确保选择安全密码:
CREATE USER myprojectuser WITH PASSWORD 'password';
OutputCREATE ROLE
接下来,我们将为刚刚创建的用户修改一些连接参数。 这将加快数据库操作,从而不必在每次建立连接时都查询和设置正确的值。
我们将默认编码设置为 Django 所期望的 UTF-8。 我们还将默认事务隔离方案设置为“已提交读”,这会阻止来自未提交事务的读取。 最后,我们正在设置时区。 默认情况下,我们的 Django 项目将设置为使用 UTC
。 这些都是来自 Django 项目本身 的所有建议:
ALTER ROLE myprojectuser SET client_encoding TO 'utf8'; ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed'; ALTER ROLE myprojectuser SET timezone TO 'UTC';
OutputALTER ROLE ALTER ROLE ALTER ROLE
现在,我们可以让我们的新用户访问管理我们的新数据库:
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
OutputGRANT
完成后,键入以下命令退出 PostgreSQL 提示:
\q
您应该返回到您的 shell 会话。
为您的项目创建 Python 虚拟环境
现在我们有了数据库,我们可以开始准备其余的项目需求。 我们将在虚拟环境中安装我们的 Python 需求,以便于管理。
为此,我们首先需要访问 virtualenv
命令。 我们可以用 pip
安装它。
如果您使用 Python 2,请键入:
sudo pip install virtualenv
如果您使用的是 Python 3,请键入:
sudo pip3 install virtualenv
安装 virtualenv
后,我们就可以开始构建我们的项目了。 创建并移动到一个目录,我们可以在其中保存我们的项目文件:
mkdir ~/myproject cd ~/myproject
在项目目录中,通过键入以下命令创建 Python 虚拟环境:
virtualenv venv
这将在您的 myproject
目录中创建一个名为 venv
的目录。 在内部,它将安装 Python 的本地版本和 pip
的本地版本。 我们可以使用它来为我们的项目安装和配置一个隔离的 Python 环境。
在我们安装项目的 Python 需求之前,我们需要激活虚拟环境。 您可以通过键入:
source venv/bin/activate
您的提示应更改以指示您现在正在 Python 虚拟环境中操作。 它看起来像这样:(venv)user@host:~/myproject$
。
在您的虚拟环境处于活动状态时,安装 Django、Gunicorn 和带有 pip
本地实例的 psycopg2
PostgreSQL 适配器:
笔记
无论你使用的是哪个版本的 Python,在激活虚拟环境时,都应该使用 pip
命令(而不是 pip3
)。
pip install django gunicorn psycopg2
这些组件将安装在我们的虚拟环境中,与我们的全局包隔离。
创建和配置一个新的 Django 项目
安装 Python 组件后,我们可以创建实际的 Django 项目文件。
创建 Django 项目
由于我们已经有一个项目目录,我们将告诉 Django 在此处安装文件。 我们现在可以在我们的 myproject
目录中启动一个 Django 项目。 这将创建一个同名的子目录来保存代码本身,并将在当前目录中创建一个管理脚本:
注意: 确保在命令末尾添加点,以便正确设置。 由于我们已经创建了一个父项目目录来保存我们的虚拟环境目录,所以我们不希望如果我们离开点将创建额外的目录级别。
django-admin.py startproject myproject .
您当前的目录结构应如下所示:
. └── ./myproject/ ├── manage.py ├── myproject/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── venv/ └── . . .
如您所见,我们有一个包含 manage.py
脚本的父项目目录、一个内部项目目录和我们之前创建的 venv
虚拟环境目录。
调整项目设置
我们应该对新创建的项目文件做的第一件事是调整设置。 在文本编辑器中打开设置文件:
nano ~/myproject/myproject/settings.py
首先找到 ALLOWED_HOSTS
指令。 这定义了可用于连接到 Django 实例的地址或域名的白名单。 任何带有不在此列表中的 Host 标头的传入请求都将引发异常。 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', . . .]
接下来,找到配置数据库访问的部分。 它将以 DATABASES
开头。 文件中的配置用于 SQLite 数据库。 我们已经为我们的项目创建了一个 PostgreSQL 数据库,所以我们需要调整设置。
使用您的 PostgreSQL 数据库信息更改设置。 我们告诉 Django 使用与 pip
一起安装的 psycopg2
适配器。 我们需要给出数据库名称、数据库用户名、数据库用户的密码,然后指定数据库位于本地计算机上。 您可以将 PORT
设置保留为空字符串:
~/myproject/myproject/settings.py
. . . DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'myproject', 'USER': 'myprojectuser', 'PASSWORD': 'password', 'HOST': 'localhost', 'PORT': '', } } . . .
接下来,向下移动到文件的底部并添加一个设置,指示静态文件的放置位置。 这是必要的,以便 Nginx 可以处理对这些项目的请求。 以下行告诉 Django 将它们放在基础项目目录中名为 static
的目录中:
~/myproject/myproject/settings.py
. . . STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
完成后保存并关闭文件。
完成初始项目设置
现在,我们可以使用管理脚本将初始数据库模式迁移到我们的 PostgreSQL 数据库:
cd ~/myproject ./manage.py makemigrations ./manage.py migrate
通过键入以下内容为项目创建管理用户:
./manage.py createsuperuser
您必须选择用户名,提供电子邮件地址,然后选择并确认密码。
我们可以通过键入以下命令将所有静态内容收集到我们配置的目录位置:
./manage.py collectstatic
您必须确认操作。 然后,静态文件将放置在项目目录中名为 static
的目录中。
注意: 在尝试开发服务器之前,请确保您在防火墙中打开了端口。
如果您碰巧正在运行 ufw
防火墙,您可以通过键入以下命令打开相应的端口:
sudo ufw allow 8000
如果您正在运行 iptables
防火墙,您需要的确切命令取决于您当前的防火墙配置。 对于 大多数配置 ,此命令应该可以工作:
sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT
最后,您可以使用以下命令启动 Django 开发服务器来测试您的项目:
./manage.py runserver 0.0.0.0:8000
在您的网络浏览器中,访问您的服务器的域名或 IP 地址,后跟 :8000
:
http://server_domain_or_IP:8000
您应该会看到默认的 Django 索引页面:
如果将 /admin
附加到地址栏中 URL 的末尾,系统将提示您输入使用 createsuperuser
命令创建的管理用户名和密码:
通过身份验证后,您可以访问默认的 Django 管理界面:
完成探索后,在终端窗口中按 CTRL-C 以关闭开发服务器。
测试 Gunicorn 为项目服务的能力
在离开我们的虚拟环境之前,我们要做的最后一件事是测试 Gunicorn 以确保它可以为应用程序服务。 我们可以通过键入以下内容轻松完成此操作:
cd ~/myproject gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application
这将在运行 Django 开发服务器的同一界面上启动 Gunicorn。 您可以返回并再次测试该应用程序。
注意: 管理界面不会应用任何样式,因为 Gunicorn 不知道对此负责的静态 CSS 内容。
我们通过指定 Django 的 wsgi.py
文件的相对目录路径向 Gunicorn 传递了一个模块,该文件是我们应用程序的入口点,使用 Python 的模块语法。 在该文件中,定义了一个名为 application
的函数,用于与应用程序通信。 要了解有关 WSGI 规范的更多信息,请单击 这里 。
完成测试后,在终端窗口中按 CTRL-C 以停止 Gunicorn。
我们现在已经完成了 Django 应用程序的配置。 我们可以通过键入以下内容退出我们的虚拟环境:
deactivate
应该从您的 shell 提示符中删除虚拟环境前缀,这表明您不再处于虚拟环境中。
创建 Gunicorn systemd 服务文件
我们已经测试过 Gunicorn 可以与我们的 Django 应用程序交互,但是我们应该实现一种更健壮的方式来启动和停止应用程序服务器。 为此,我们将制作一个 systemd 服务文件。
在您的文本编辑器中使用 sudo
权限为 Gunicorn 创建并打开一个 systemd 服务文件:
sudo nano /etc/systemd/system/gunicorn.service
从 [Unit]
部分开始,用于指定元数据和依赖项。 我们将在此处描述我们的服务,并告诉 init 系统仅在达到网络目标后才启动它:
/etc/systemd/system/gunicorn.service
[Unit] Description=gunicorn daemon After=network.target
接下来,我们将打开 [Service]
部分。 我们将指定要在其下运行的用户和组。 由于它拥有所有相关文件,因此我们将授予我们常规用户帐户对该过程的所有权。 我们将组所有权授予 www-data
组,以便 Nginx 可以轻松地与 Gunicorn 通信。
然后,我们将绘制工作目录并指定用于启动服务的命令。 在这种情况下,我们必须指定 Gunicorn 可执行文件的完整路径,该可执行文件安装在我们的虚拟环境中。 由于 Nginx 安装在同一台计算机上,因此我们将其绑定到项目目录中的 Unix 套接字。 这比使用网络端口更安全、更快捷。 我们还可以在此处指定任何可选的 Gunicorn 调整。 例如,我们在这种情况下指定了 3 个工作进程:
/etc/systemd/system/gunicorn.service
[Unit] Description=gunicorn daemon After=network.target [Service] User=sammy Group=www-data WorkingDirectory=/home/sammy/myproject ExecStart=/home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application
最后,我们将添加一个 [Install]
部分。 如果我们允许它在启动时启动,这将告诉 systemd 将该服务链接到什么。 我们希望在常规多用户系统启动并运行时启动此服务:
/etc/systemd/system/gunicorn.service
[Unit] Description=gunicorn daemon After=network.target [Service] User=sammy Group=www-data WorkingDirectory=/home/sammy/myproject ExecStart=/home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application [Install] WantedBy=multi-user.target
至此,我们的 systemd 服务文件就完成了。 现在保存并关闭它。
我们现在可以启动我们创建的 Gunicorn 服务并启用它,以便它在启动时启动:
sudo systemctl start gunicorn sudo systemctl enable gunicorn
OutputCreated symlink from /etc/systemd/system/multi-user.target.wants/gunicorn.service to /etc/systemd/system/gunicorn.service.
通过键入以下内容检查服务的状态:
sudo systemctl status gunicorn
Output● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled) Active: active (running) since Wed 2016-12-21 21:05:07 UTC; 49s ago Main PID: 10154 (gunicorn) CGroup: /system.slice/gunicorn.service ├─10154 /home/sammy/myproject/venv/bin/python3 /home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application ├─10157 /home/sammy/myproject/venv/bin/python3 /home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application ├─10158 /home/sammy/myproject/venv/bin/python3 /home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application └─10159 /home/sammy/myproject/venv/bin/python3 /home/sammy/myproject/venv/bin/gunicorn --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application Dec 21 21:05:07 debian-512mb-nyc3-01 systemd[1]: Started gunicorn daemon. Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Starting gunicorn 19.6.0 Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Listening at: unix:/home/sammy/myproject/myproject.sock (10154) Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10154] [INFO] Using worker: sync Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10157] [INFO] Booting worker with pid: 10157 Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10158] [INFO] Booting worker with pid: 10158 Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: [2016-12-21 21:05:07 +0000] [10159] [INFO] Booting worker with pid: 10159
要寻找的最重要的事情是该单元处于活动状态。
现在也是检查套接字文件是否已创建的好时机。 如果您列出 ~/myproject
目录的内容,您应该会看到 Unix 套接字文件:
ls -l ~/myproject
Outputtotal 16 -rwxr-xr-x 1 sammy sammy 807 Dec 21 20:46 manage.py drwxr-xr-x 3 sammy sammy 4096 Dec 21 20:54 myproject srwxrwxrwx 1 sammy www-data 0 Dec 21 21:05 myproject.sock drwxr-xr-x 3 sammy sammy 4096 Dec 21 20:54 static drwxr-xr-x 5 sammy sammy 4096 Dec 21 20:41 venv
如您所见,套接字在那里并且 www-data
组具有组所有权。
将 Nginx 配置为代理传递到 Gunicorn
现在 Gunicorn 已经设置好了,我们需要配置 Nginx 以将流量传递给进程。
首先在 Nginx 的 sites-available
目录中创建并打开一个新的服务器块:
sudo nano /etc/nginx/sites-available/myproject
在里面,打开一个新的服务器块。 我们将首先指定此块应侦听普通端口 80,并应响应我们服务器的域名或 IP 地址:
/etc/nginx/sites-available/myproject
server { listen 80; server_name server_domain_or_IP; }
接下来,如果找不到 favicon,我们可以告诉 Nginx 忽略错误。 我们还将告诉它在哪里可以找到我们在 ~/myproject/static
目录中收集的静态资产。 所有这些文件都有一个标准的 URI 前缀“/static”,所以我们可以创建一个位置块来匹配这些请求:
/etc/nginx/sites-available/myproject
server { listen 80; server_name server_domain_or_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/sammy/myproject; } }
最后,我们将创建一个 location / {}
块来匹配所有其他请求。 在这个位置中,我们将包含 Nginx 安装中包含的标准 proxy_params
文件,然后我们会将流量传递到 Gunicorn 进程创建的套接字:
/etc/nginx/sites-available/myproject
server { listen 80; server_name server_domain_or_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/sammy/myproject; } location / { include proxy_params; proxy_pass http://unix:/home/sammy/myproject/myproject.sock; } }
完成后保存并关闭文件。 现在,我们可以通过将文件链接到 sites-enabled
目录来启用该文件:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
通过键入以下内容测试您的 Nginx 配置是否存在语法错误:
sudo nginx -t
Outputnginx: 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
注意:如果您启用了防火墙,请调整它以再次删除端口8000并允许正常访问端口80。
如果您碰巧正在运行 ufw
防火墙,您可以通过键入以下命令打开相应的端口:
sudo ufw delete allow 8000 sudo ufw allow 'WWW'
如果您正在运行 iptables
防火墙,您需要的确切命令取决于您当前的防火墙配置。 对于 大多数配置 ,这些命令应该可以工作:
sudo iptables -D INPUT -p tcp --dport 8000 -j ACCEPT sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
您现在应该能够转到服务器的域或 IP 地址来查看您的应用程序,而无需指定端口。
笔记
配置 Nginx 后,下一步应该是使用 SSL/TLS 保护到服务器的流量。 这很重要,因为没有它,包括密码在内的所有信息都会以纯文本形式通过网络发送。
如果您有域名,获得 SSL 证书以保护您的流量的最简单方法是使用 Let's Encrypt。 按照本指南在 Debian 8 上 设置 Let's Encrypt with Nginx。
如果您没有域名,您仍然可以使用 自签名 SSL 证书 保护您的站点以进行测试和学习。
结论
在本指南中,我们在自己的虚拟环境中设置了一个 Django 项目。 我们已经配置 Gunicorn 来翻译客户端请求,以便 Django 可以处理它们。 之后,我们设置 Nginx 作为反向代理来处理客户端连接并根据客户端请求为正确的项目提供服务。
Django 通过提供许多通用部分使创建项目和应用程序变得简单,让您可以专注于独特的元素。 通过利用本文中描述的通用工具链,您可以轻松地为您从单个服务器创建的应用程序提供服务。