如何在Debian 8上使用Postgres,Nginx和Gunicorn设置Django

介绍

Django是一个功能强大的Web框架,可以帮助您完成Python应用程序或网站。Django包含一个简化的开发服务器,用于在本地测试您的代码,但是对于任何与生产相关的细节,都需要一个更安全,更强大的Web服务器。

在本教程中,我们将演示如何在Debian 8上安装和配置某些组件以支持和服务Django应用程序。我们将设置PostgreSQL数据库,而不是使用默认的SQLite数据库。我们将配置Gunicorn应用程序服务器以与我们的应用程序连接。然后,我们将设置Nginx以反向代理Gunicorn,让我们可以访问其安全性和性能功能来为我们的应用程序提供服务。

准备和目标

一台已经设置好可以使用sudo命令的非root账号的Debian 8服务器。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器

我们将在虚拟环境中安装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的操作系统用户,以对应postgresPostgreSQL管理用户。我们需要使用此用户来执行管理任务。我们可以使用sudo命令并使用-u选项传递用户名。

输入以下内容登录交互式Postgres会话:

$ sudo -u postgres psql

您将获得一个PostgreSQL提示,我们便可以在其中设置我们的要求。

首先,为您的项目创建一个数据库:

注意:每个Postgres语句必须以分号结尾,因此请确保您的命令避免出现错误。

postgres=# CREATE DATABASE myproject;
Output
CREATE DATABASE

接下来,为我们的项目创建一个数据库用户。确保选择安全的密码:

postgres=# CREATE USER myprojectuser WITH PASSWORD 'password';
Output
CREATE ROLE

接下来,我们将为刚刚创建的用户修改一些连接参数。这将加速数据库操作,以便每次建立连接时都不必再次查询和设置正确的值。

我们将默认编码设置为Django所期望的UTF-8。我们还将默认事务隔离方案设置为“read committed”,它阻止从未提交的事务中读取。最后,我们会设定时区。默认情况下,我们的Django项目将设置为使用UTC

postgres=# ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
postgres=# ALTER ROLE myprojectuser SET timezone TO 'UTC';
Output
ALTER ROLE
ALTER ROLE
ALTER ROLE

现在,我们可以为新用户提供管理新数据库的权限:

postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
Output
GRANT

完成后,输入以下命令退出PostgreSQL提示符:

postgres=# \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$

在您的虚拟环境处于活动状态时,使用pip的本地实例安装Django,Gunicorn和psycopg2 PostgreSQL 适配器:

注意:无论您使用的是哪个版本的Python,在激活虚拟环境时,都应该使用pip命令(不是pip3)。

(venv) $ pip install django gunicorn psycopg2

这些组件将安装在我们的虚拟环境中,与我们的全局软件包隔离。

创建和配置一个新的Django项目

安装我们的Python组件后,我们可以创建实际的Django项目文件。

创建Django项目

由于我们已经有了一个项目目录,我们将告诉Django在这里安装文件。我们现在可以在我们的myproject目录中启动Django项目。这将创建一个同名的子目录来保存代码本身,并将在当前目录中创建一个管理脚本:

注意:确保在命令末尾添加句点,以便可以正确设置。由于我们已经创建了一个主项目目录来保存我们的虚拟环境目录,因此如果我们不加句点,则会导致创建额外的目录级别。

(venv) $ django-admin.py startproject myproject .

您当前的目录结构应如下所示:

.
 └── ./myproject/
    ├── manage.py
    ├── myproject/
    │   ├── init.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── venv/
        └── . . .

如您所见,我们有一个主项目目录,其中包含manage.py脚本,内部项目目录以及我们之前创建的虚拟环境目录venv

调整项目设置

我们应该对新创建的项目文件做的第一件事就是调整设置。在文本编辑器中打开设置文件:

(venv) $ nano ~/myproject/myproject/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', . . .]

接下来,找到配置数据库访问的部分。它将从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数据库:

(venv) $ cd ~/myproject
(venv) $ ./manage.py makemigrations
(venv) $ ./manage.py migrate

输入以下内容为项目创建管理用户:

(venv) $ ./manage.py createsuperuser

您必须选择用户名,提供电子邮件地址,然后选择并确认密码。

我们可以通过输入以下内容将所有静态内容收集到我们配置的目录位置:

(venv) $ ./manage.py collectstatic

您必须确认操作。然后,静态文件将放在项目目录中名为static的目录中。

注意:在尝试开发服务器之前,请确保打开防火墙中的端口。 如果您正在运行的是ufw防火墙,可以通过输入以下命令打开相应的端口: (venv) $ sudo ufw allow 8000 如果您运行的是iptables防火墙,则所需的确切命令取决于您当前的防火墙配置。对于大部分配置,此命令应该可行: (venv) $ sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT

最后,您可以使用以下命令启动Django开发服务器来测试您的项目:

(venv) $ ./manage.py runserver 0.0.0.0:8000

在Web浏览器中,访问服务器的域名或IP地址,后面跟随:8000

http://server_domain_or_IP:8000

您应该看到默认的Django索引页面:

如果您将/admin添加到地址栏中URL的末尾,系统将提示您输入使用createsuperuser命令创建的管理用户名和密码:

进行身份验证后,您可以访问默认的Django管理界面:

完成浏览后,在终端窗口中按CTRL-C关闭开发服务器。

测试Gunicorn服务项目的能力

在离开我们的虚拟环境之前,我们要做的最后一件事是测试Gunicorn以确保它可以为应用程序提供服务。我们可以通过输入以下内容完成:

(venv) $ cd ~/myproject
(venv) $ gunicorn --bind 0.0.0.0:8000 myproject.wsgi:application

这将在运行Django开发服务器的同一界面上启动Gunicorn。您可以返回并再次测试应用程序。

注意:管理界面不会应用任何样式,因为Gunicorn不知道负责此操作的静态CSS内容。

我们通过使用Python的模块语法指定Django的wsgi.py文件的相对目录路径来传递给Gunicorn一个模块,该文件是我们应用程序的入口点。在此文件内部,定义了一个名为application的函数,该函数用于与应用程序通信。

完成测试后,在终端窗口中按CTRL-C以停止Gunicorn。

我们现在已经完成了Django应用程序的配置。我们可以通过输入以下命令退出虚拟环境:

(venv) $ 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可执行文件的完整路径,而该文件安装在我们的虚拟环境中。我们将它绑定到项目目录中的Unix套接字,因为Nginx也安装在同一台计算机上。这比使用网络端口更安全,更快捷。我们还可以在这里指定任何可选的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
Output
Created 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 [INFO] Starting gunicorn 19.6.0
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: 2016-12-21 21:05:07 +0000 [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 [INFO] Using worker: sync
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: 2016-12-21 21:05:07 +0000 [INFO] Booting worker with pid: 10157
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: 2016-12-21 21:05:07 +0000 [INFO] Booting worker with pid: 10158
Dec 21 21:05:07 debian-512mb-nyc3-01 gunicorn[10154]: 2016-12-21 21:05:07 +0000 [INFO] Booting worker with pid: 10159

最重要的就是确定该单位是活跃的。

现在也是检查套接字文件是否已创建的好时机。如果列出~/myproject目录的内容,则应该看到Unix套接字文件:

$ ls -l ~/myproject
Output
total 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
Output
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

注意:如果启用了防火墙,请将其调整为再次删除端口8000,并允许对端口80进行正常访问。 如果您正在运行ufw防火墙,可以通过输入以下命令打开相应的端口: (venv) $ sudo ufw delete allow 8000 (venv) $ sudo ufw allow 'WWW' 如果您运行的是iptables防火墙,则所需的确切命令取决于您当前的防火墙配置。对于大多数配置,这些命令应该可行: (venv) $ sudo iptables -D INPUT -p tcp --dport 8000 -j ACCEPT (venv) $ sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT

您现在应该可以转到服务器的域或IP地址来查看应用程序,而无需指定端口。

注意 配置Nginx后,下一步应该是使用SSL / TLS保护服务器的流量。这很重要,因为如果没有它,所有信息(包括密码)都以纯文本形式通过网络发送。 如果您有域名,获取SSL证书以确保流量安全的最简单方法是使用Let's Encrypt。 如果您没有域名,您仍然可以使用自签名SSL证书Apache创建自签名SSL证书如何为Nginx创建自签名SSL证书保护您的站点以进行测试和学习。

结论

在本教程中,我们在自己的虚拟环境中设置了一个Django项目。我们已经配置了Gunicorn来翻译客户端请求,以便Django可以处理它们。之后,我们将Nginx设置为反向代理,以处理客户端连接并根据客户端请求提供正确的项目。

Django通过提供许多常见的部分使创建项目和应用程序变得简单,使您可以专注于其拥有的独特的组件。通过利用本文中介绍的常规工具链,您可以轻松地为从单个服务器创建的应用程序提供服务。

自建服务器难免会遇到这样的问题,配置SSL很麻烦,虽然对一部分人来说这也是一种乐趣,但是如果您在生产环境使用,我还是建议您直接使用云关系型数据库,云关系型数据库让您在云中轻松部署、管理和扩展的关系型数据库,提供安全可靠、伸缩灵活的按需云数据库服务。腾讯云关系型数据库提供 MySQL、SQL Server、MariaDB、PostgreSQL 数据库引擎,并针对数据库引擎的性能进行了优化。云关系型数据库是一种高度可用的托管服务,提供容灾、备份、恢复、监控、迁移等数据库运维全套解决方案,可将您从耗时的数据库管理任务中解放出来,让您有更多时间专注于您的应用和业务。

更多Linux教程请前往腾讯云+社区学习更多知识。


参考文献:《How To Set Up Django with Postgres, Nginx, and Gunicorn on Debian 8 》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏禁心尽力

持久层框架之MyBatis

1、mybatis框架介绍:   MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software founda...

27750
来自专栏Porschev[钟慰]的专栏

Windows Server 2008 R2 配置AD(Active Directory)域控制器

配置环境 Windows版本:Windows Server 2008 R2 Enterprise                      S...

54350
来自专栏北京马哥教育

史上最详细linux启动过程讲解---没有之一

对于linux系统的初学者来说,理解并掌握linux系统启动流程能够使你够深入的理解linux系统,还可以通过系统的启动过程来分析问题解决问题。 Linux...

39760
来自专栏猿人谷

mac下使用github

      提起github相信大家都不会陌生,在这里就不再赘述了。作为开源代码库以及版本控制系统,使用好了确实会非常受益,再说的势利点,你找工作时给面试官说你...

21350
来自专栏散尽浮华

Linux操作系统启动流程梳理

接触linux系统运维已经好几年了,常常被问到linux系统启动流程问题,刚好今天有空来梳理下这个过程: 一般来说,所有的操作系统的启动流程基本就是: ? 总的...

30180
来自专栏丑胖侠

Spring boot 数据源未配置异常

问题 在使Springboot自动生成的项目框架时如果选择了数据源,比如选择了mysql,生成项目之后,启动会报一下异常: Description: Cann...

34080
来自专栏Petrichor的专栏

ubuntu: scp指令 (远程拷贝)

用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。当你服务器硬盘变为只读 read...

35820
来自专栏Brian

Linux DNS之nslookup命令

---- 概述 在我文章中有一篇专门讲解DNS如何工作的,今天我们采用linux下nslookup工具来查询DNS。nslookup全称是”query Inte...

48250
来自专栏Brian

Install Django Nginx uWSGI

概述 最近项目需要安装和配置多站点环境,所以把多站点开发环境配置和安装记录下来,帮助其他人少走坑。 安装Python 2.7.x 首先安装一些开发环境基本的包和...

40590
来自专栏Java学习123

IBM Websphere Message Broker(MB) 教程系列-(1) 在Fedora

390100

扫码关注云+社区

领取腾讯云代金券