介绍

Django是一个功能强大的Web框架,可以帮助您快速启动Python应用程序或网站。它包括一些方便的功能,例如对象关系映射器,Python API和适用于您的应用程序的可自定义管理界面。它还包括一个缓存框架,并通过其URL Dispatcher和Template系统鼓励进行干净的应用程序设计。

Django开箱即用,包括用于测试和本地开发的最小的Web服务器,但应与用于生产用例的更强大的服务基础架构配对。 Django经常与Nginx Web服务器一起部署,以处理静态文件请求和HTTPS重定向,而Gunicorn WSGI服务器则为应用程序提供服务。

在本指南中,我们将通过将静态文件(例如Javascript和CSS样式表)卸载到DigitalOcean Spaces,并可选地使用C交付网络(CDN)来交付这些设置,以将这些文件存储在最终用户附近以减少传输时间。我们还将使用DigitalOcean托管PostgreSQL数据库作为数据存储,以简化数据层并避免手动配置可伸缩的PostgreSQL数据库。

先决条件

在开始本指南之前,您应该具备以下功能:

  • 具有基本防火墙和配置了sudo权限的非root用户的全新Ubuntu 18.04服务器实例。您可以通过运行Ubuntu 18.04的初始服务器设置来学习如何进行设置。
  • DigitalOcean托管的PostgreSQL集群。要了解如何创建集群,请查阅DigitalOcean托管数据库产品文档。
  • 一个DigitalOcean空间,用于存储Django项目的静态文件和该空间的访问密钥集。要了解如何创建空间,请查阅如何创建空间产品文档,并要了解如何为空间创建访问键,请参阅与访问键共享对空间的访问。
  • Nginx已在您的服务器上安装,保护和配置为使用您选择的域名。有关使用Let's Encrypt设置A记录和保护Nginx安装的更多信息,请参见如何在Ubuntu 18.04上使用Let's Encrypt保护Nginx。

第1步—从Ubuntu存储库安装软件包

首先,我们将从Ubuntu存储库中下载并安装所需的所有项目。稍后,我们将使用Python软件包管理器pip安装其他组件。

我们需要先更新本地apt软件包索引,然后下载并安装软件包。

在本指南中,我们将Django与Python 3结合使用。要安装必要的库,请登录服务器并输入:

  • sudo apt update
  • sudo apt install python3-pip python3-dev libpq-dev curl postgresql-client

这将安装pip,构建Gunicorn所需的Python开发文件,构建Pyscopg PostgreSQL Python适配器所需的libpq头文件以及PostgreSQL命令行客户端。

提示开始下载和安装软件包时,请按Y,然后按Enter。

接下来,我们将配置数据库以与Django应用一起使用。

第2步-创建PostgreSQL数据库和用户

现在,我们将为Django应用程序创建一个数据库和数据库用户。

首先,通过从Cloud Control Panel导航到Databases,然后单击进入数据库,获取集群的Connection Parameters。您应该看到一个Connection Details框,其中包含群集的一些参数。注意这些。

返回命令行,使用以下凭据和我们刚安装的psql PostgreSQL客户端登录到集群:

  • psql -U username -h host -p port -d database -set=sslmode=require

出现提示时,输入显示在Postgres用户名旁边的密码,然后按ENTER键。

系统将显示一个PostgreSQL提示,您可以从中管理数据库。

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

  • CREATE DATABASE polls;

注意:每个Postgres语句都必须以分号结尾,因此,如果遇到问题,请确保命令以1结尾。

现在,我们可以切换到民意调查数据库:

  • \c polls;

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

  • CREATE USER myprojectuser WITH PASSWORD 'password';

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

我们将Django期望的默认编码设置为UTF-8。我们还将默认事务隔离方案设置为“已读读”,这会阻止未提交事务的读操作。最后,我们设置时区。默认情况下,我们的Django项目将设置为使用UTC。这些都是Django项目本身的建议。

在PostgreSQL提示符下输入以下命令:

  • 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';

现在,我们可以授予新用户访问权限来管理新数据库:

  • GRANT ALL PRIVILEGES ON DATABASE polls TO myprojectuser;

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

  • \q

Your Django app is now ready to connect to and manage this database.

在下一步中,我们将安装virtualenv并为Django项目创建一个Python虚拟环境。

步骤3 —为您的项目创建Python虚拟环境

现在,我们已经设置了数据库来与我们的应用程序一起使用,我们将创建一个Python虚拟环境,该虚拟环境会将该项目的依赖项与系统的全局Python安装隔离开。

为此,我们首先需要访问virtualenv命令。我们可以使用pip安装它。

通过输入以下内容来升级pip并安装软件包:

  • sudo -H pip3 install --upgrade pip
  • sudo -H pip3 install virtualenv

安装virtualenv后,我们可以创建一个目录来存储我们的Python虚拟环境,并使其与Django polls应用程序一起使用。

创建一个名为envs的目录并导航到其中:

  • mkdir envs
  • cd envs

在此目录中,通过键入以下内容来创建一个称为polls的Python虚拟环境:

  • virtualenv polls

这将在envs目录中创建一个名为polls的目录。在内部,它将安装Python的本地版本和pip的本地版本。我们可以使用它为我们的项目安装和配置一个隔离的Python环境。

在安装项目的Python要求之前,我们需要激活虚拟环境。您可以通过键入以下内容进行操作:

  • source polls/bin/activate

您的提示应更改为指示您现在在Python虚拟环境中进行操作。它看起来像这样:(轮询)用户@ host:〜/ envs $。

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

注意:激活虚拟环境后(当提示符之前有(轮询)提示时),即使使用的是Python 3,也请使用pip而不是pip3。该工具的虚拟环境副本始终命名为pip,而与Python无关版。

  • pip install django gunicorn psycopg2-binary

现在,您应该拥有运行Django polls应用程序所需的所有软件。在下一步中,我们将创建一个Django项目并安装此应用。

第4步-创建民意调查Django应用程序

现在,我们可以设置示例应用程序。在本教程中,我们将使用Django文档中的Polls演示应用程序。它由允许用户查看民意调查和投票的公共站点,以及允许管理员修改,创建和删除民意调查的管理控制面板组成。

在本指南中,我们将跳过教程步骤,仅从DigitalOcean Community django-polls repo克隆最终应用程序。

如果您想手动完成这些步骤,请在主目录中创建一个名为django-polls的目录并导航至该目录:

  • cd
  • mkdir django-polls
  • cd django-polls

从那里,您可以按照官方Django文档中的编写第一个Django应用程序教程进行操作。完成后,请跳至步骤5。

如果您只想克隆完成的应用程序,请导航到主目录,然后使用git克隆django-polls存储库:

  • cd
  • git clone https://github.com/do-community/django-polls.git

cd进入其中,并列出目录内容:

  • cd django-polls
  • ls

您应该看到以下对象:

Output
LICENSE README.md manage.py mysite polls templates

manage.py是用于操纵应用程序的主要命令行实用程序。 polls包含polls应用程序代码,而mysite包含项目范围的代码和设置。模板包含用于管理界面的定制模板文件。要了解有关项目结构和文件的更多信息,请参阅官方Django文档中的创建项目。

在运行该应用程序之前,我们需要调整其默认设置并将其连接到我们的数据库。

步骤5 —调整应用程序设置

在此步骤中,我们将修改Django项目的默认配置以提高安全性,将Django连接到我们的数据库,并将静态文件收集到本地目录中。

首先在文本编辑器中打开设置文件:

  • nano ~/django-polls/mysite/settings.py

首先找到ALLOWED_HOSTS指令。这定义了要用于连接到Django实例的地址或域名的列表。主机头不在此列表中的传入请求将引发异常。 Django要求您对此进行设置,以防止出现某类安全漏洞。

在方括号中,列出与Django服务器关联的IP地址或域名。每个项目都应以引号列出,各条目之间用逗号分隔。您的列表还将包括localhost,因为您将通过本地Nginx实例代理连接。如果您希望包括对整个域和任何子域的请求,请在条目的开头加上句点。

在下面的代码段中,有一些注释掉的示例说明了这些条目的外观:

~/django-polls/mysite/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', . . ., 'localhost']

. . . 

接下来,找到配置数据库访问的文件部分。它将以DATABASES开头。该文件中的配置适用于SQLite数据库。我们已经为我们的项目创建了一个PostgreSQL数据库,因此我们需要调整这些设置。

我们将告诉Django使用与pip一起安装的psycopg2数据库适配器,而不是默认的SQLite引擎。我们还将重复使用步骤2中引用的连接参数。您始终可以从DigitalOcean Cloud Control Panel的Managed Databases部分中找到此信息。

使用数据库设置更新文件:数据库名称(polls),数据库用户名,数据库用户的密码以及数据库主机和端口。确保用您自己的信息替换特定于数据库的值:

~/django-polls/mysite/settings.py
. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'polls',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'managed_db_host',
        'PORT': 'managed_db_port',
    }
}

. . .

接下来,向下移动到文件底部,并添加一个指示应将静态文件放置在何处的设置。这是必需的,以便Nginx可以处理对这些项目的请求。以下代码行告诉Django将它们放置在基础项目目录中名为static的目录中:

~/django-polls/mysite/settings.py
. . .

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')

完成后保存并关闭文件。

至此,您已经配置了Django项目的数据库,安全性和静态文件设置。如果您从一开始就遵循民意测验教程,但没有克隆GitHub存储库,则可以继续执行第6步。如果克隆了GitHub存储库,则还有一个步骤。

Django设置文件包含SECRET_KEY变量,该变量用于为各种Django对象创建哈希。重要的是将其设置为唯一且不可预测的值。 SECRET_KEY变量已从GitHub存储库中清除,因此我们将使用django Python程序包内置的名为get_random_secret_key()的函数创建一个新变量。在命令行中,打开一个Python解释器:

  • python

您应该看到以下输出并提示:

Output
Python 3.6.7 (default, Oct 22 2018, 11:32:17) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>>

从Django包中导入get_random_secret_key函数,然后调用该函数:

  • from django.core.management.utils import get_random_secret_key
  • get_random_secret_key()

将生成的密钥复制到剪贴板。

按下CTRL + D退出Python解释器。

接下来,再次在文本编辑器中打开设置文件:

nano ~/django-polls/mysite/settings.py

找到SECRET_KEY变量,然后粘贴刚刚生成的密钥:

~/django-polls/mysite/settings.py
. . .

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'your_secret_key_here'

. . .

保存并关闭文件。

现在,我们将使用Django开发服务器在本地测试该应用,以确保所有内容均已正确配置。

第6步-测试应用

在运行Django开发服务器之前,我们需要使用manage.py实用程序创建数据库架构并将静态文件收集到STATIC_ROOT目录中。

导航到项目的基本目录,然后使用makemigrations和migration命令在我们的PostgreSQL数据库中创建初始数据库架构:

  • cd django-polls
  • ./manage.py makemigrations
  • ./manage.py migrate

makemigrations将基于对Django模型的更改来创建迁移或数据库架构更改。迁移会将这些迁移应用于数据库架构。要了解有关Django中迁移的更多信息,请参阅Django官方文档中的Migrations。

通过键入以下内容为项目创建一个管理用户:

  • ./manage.py createsuperuser

You will have to select a username, provide an email address, and choose and confirm a password.

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

  • ./manage.py collectstatic

然后,静态文件将放置在项目目录中名为static的目录中。

如果您遵循初始服务器设置指南,则应该拥有用于保护服务器的UFW防火墙。为了测试开发服务器,我们必须允许访问将要使用的端口。

通过键入以下内容为端口8000创建一个例外:

  • sudo ufw allow 8000

使用Django开发服务器测试应用

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

  • ./manage.py runserver 0.0.0.0:8000

在网络浏览器中,访问服务器的域名或IP地址,后跟:8000和轮询路径:

  • http://server_domain_or_IP:8000/polls

您应该看到“轮询”应用程序界面:

要检出管理界面,请访问服务器的域名或IP地址,后跟:8000和管理界面的路径:

  • http://server_domain_or_IP:8000/admin

您应该看到“轮询应用程序管理员身份验证”窗口:

输入您使用createsuperuser命令创建的管理用户名和密码。

验证之后,您可以访问“轮询”应用程序的管理界面:

探索完成后,请在终端窗口中按CTRL-C以关闭开发服务器。

使用Gunicorn测试应用

在卸载静态文件之前,我们要做的最后一件事是测试Gunicorn,以确保它可以为应用程序提供服务。为此,我们可以输入项目目录并使用gunicorn加载项目的WSGI模块:

  • gunicorn --bind 0.0.0.0:8000 mysite.wsgi

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

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

我们通过指定Django的wsgi.py文件(我们应用程序的入口)的相对目录路径,向Gunicorn传递了一个模块。该文件定义了一个称为application的函数,该函数与该应用程序通信。要了解有关WSGI规范的更多信息,请单击此处。

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

现在,我们将应用程序的静态文件卸载到DigitalOcean Spaces。

步骤7 —将静态文件卸载到DigitalOcean空间

此时,Gunicorn可以服务我们的Django应用程序,但不能服务其静态文件。通常,我们将Nginx配置为提供这些文件,但是在本教程中,我们将使用django-storages插件将其卸载到DigitalOcean Spaces。这使您可以通过集中化Django的静态内容并释放服务器资源来轻松扩展Django。此外,您可以使用DigitalOcean Spaces CDN交付此静态内容。

有关将Django静态文件卸载到对象存储的完整指南,请参阅如何使用Django设置对象存储。

安装和配置django-storages

我们将从安装django-storages Python软件包开始。 django-storages软件包为Django提供了S3Boto3Storage存储后端,该后端使用boto3库将文件上传到任何与S3兼容的对象存储服务。

首先,使用pip安装django-storages和boto3 Python软件包:

  • pip install django-storages boto3

接下来,再次打开应用的Django设置文件:

  • nano ~/django-polls/mysite/settings.py

向下导航至文件的INSTALLED_APPS部分,然后将存储追加到已安装应用的列表中:

~/django-polls/mysite/settings.py
. . .

INSTALLED_APPS = [
    . . .
    'django.contrib.staticfiles',
    'storages',
]

. . .

向下滚动文件至我们先前修改的STATIC_URL。现在,我们将覆盖这些值,并附加新的S3Boto3Storage后端参数。删除您之前输入的代码,然后添加以下块,其中包括您Space的访问和位置信息。请记住用您自己的信息替换此处突出显示的值:

~/django-polls/mysite/settings.py
. . .

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

AWS_ACCESS_KEY_ID = 'your_spaces_access_key'
AWS_SECRET_ACCESS_KEY = 'your_spaces_secret_key'

AWS_STORAGE_BUCKET_NAME = 'your_space_name'
AWS_S3_ENDPOINT_URL = 'spaces_endpoint_URL'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

STATIC_URL = '{}/{}/'.format(AWS_S3_ENDPOINT_URL, AWS_LOCATION)
STATIC_ROOT = 'static/'

我们定义以下配置项:

  • AWS_ACCESS_KEY_ID:您在本教程先决条件中创建的Space的访问密钥ID。如果您没有创建一组访问键,请参阅与访问键共享对空间的访问。
  • AWS_SECRET_ACCESS_KEY:DigitalOcean空间的秘密密钥。
  • AWS_STORAGE_BUCKET_NAME:您的DigitalOcean Space名称。
  • AWS_S3_ENDPOINT_URL:用于访问对象存储服务的端点URL。对于DigitalOcean,这取决于空间区域,类似于https://nyc3.digitaloceanspaces.com。
  • AWS_S3_OBJECT_PARAMETERS设置静态文件上的缓存控制标头。
  • AWS_LOCATION:在对象存储桶中定义一个目录,所有静态文件都将放置在该目录中。
  • AWS_DEFAULT_ACL:定义静态文件的访问控制列表(ACL)。将其设置为公开读取可确保最终用户可以公开访问这些文件。
  • STATICFILES_STORAGE:设置Django将用于卸载静态文件的存储后端。该后端应与任何与S3兼容的后端(包括DigitalOcean Spaces)一起使用。
  • STATIC_URL:指定Django在为静态文件生成URL时应使用的基本URL。在这里,我们结合端点URL和静态文件子目录来构造静态文件的基本URL。
  • STATIC_ROOT:指定将静态文件复制到对象存储之前在本地收集静态文件的位置。

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

从现在开始,当您运行collectstatic时,Django会将您应用的静态文件上传到Space。当您启动Django时,它将开始从该Space提供静态资产,例如CSS和Javascript。

在下一部分中,我们将为此空间启用CDN,并可以选择为Spaces CDN配置自定义子域。通过跨地理位置分布的边缘服务器网络缓存Django项目的静态文件,可以加快其交付速度。要了解有关CDN的更多信息,请参阅《使用CDN加快静态内容交付》。如果您不想启用Spaces CDN,请跳到配置CORS标头。

启用CDN(可选)

要通过DigitalOcean Spaces CDN激活静态文件传递,请先为DigitalOcean Space启用CDN。若要了解如何执行此操作,请参阅DigitalOcean产品文档中的“如何启用Spaces CDN”。

如果您想将自定义域与Spaces CDN一起使用,请遵循如何使用子域自定义Spaces CDN端点来创建子域CNAME记录和适当的SSL证书。

强烈建议对Spaces CDN使用自定义域。通过使卸载的资产URL与Django网站的URL相似,可以大大改善您网站的搜索引擎优化(SEO)。要将自定义域与Spaces CDN一起使用,需要确保首先将域添加到DigitalOcean帐户。要了解如何执行此操作,请参阅如何添加域。

Once you’ve enabled the CDN for your Space and optionally created a custom subdomain for it, navigate to your Space using the Cloud Control Panel . You should see a new Endpoints link under your Space name:

这些端点应包含您的空间名称。如果您为Spaces CDN创建了一个自定义子域,则此列表将包含一个名为Subdomain的附加终结点。

Edge端点通过CDN路由对Spaces对象的请求,并尽可能多地从边缘缓存中为它们服务。记下该Edge端点,因为我们将使用它来配置django-storages插件。如果您为Spaces CDN创建了子域,则子域终结点是此Edge终结点的别名。

接下来,再次编辑应用程序的Django设置文件:

  • nano ~/django-polls/mysite/settings.py

导航到我们最近修改的“静态文件”部分。添加AWS_S3_CUSTOM_DOMAIN参数以配置django-storages插件CDN端点,并更新STATIC_URL参数以使用此新的CDN端点:

~/django-polls/mysite/settings.py
. . .

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

# Moving static assets to DigitalOcean Spaces as per:
# https://www.digitalocean.com/community/tutorials/how-to-set-up-object-storage-with-django
AWS_ACCESS_KEY_ID = 'your_spaces_access_key'
AWS_SECRET_ACCESS_KEY = 'your_spaces_secret_key'

AWS_STORAGE_BUCKET_NAME = 'your_space_name'
AWS_S3_ENDPOINT_URL = 'spaces_endpoint_URL'
AWS_S3_CUSTOM_DOMAIN = 'spaces_edge_endpoint_URL'
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

STATIC_URL = '{}/{}/'.format(AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATIC_ROOT = 'static/'

在这里,将空格_edge_endpoint_URL替换为刚才记下的Edge端点,并截断https://前缀。例如,如果Edge端点URL为https:// example.sfo2 .cdn.digitaloceanspaces.com,则应将AWS_S3_CUSTOM_DOMAIN设置为example.sfo2 .cdn.digitaloceanspaces.com。

如果创建了自定义子域,请用自定义子域终结点替换spaces_edge_endpoint_URL,并截断https://前缀。例如,如果子域端点URL为https:// assets .example.com,则应将AWS_S3_CUSTOM_DOMAIN设置为assets .example.com。

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

当您启动Django时,它将使用CDN为您的DigitalOcean Space提供静态内容。

在测试所有功能是否正常运行之前,我们需要为我们的Spaces文件配置跨域资源共享(CORS)标头,否则您的Web浏览器可能会拒绝访问某些静态资产。如果您将自定义子域与Spaces CDN一起用于Django使用的相同域,则可以直接跳至测试Spaces静态文件传递。

配置CORS头

CORS标头告诉Web浏览器,在一个域中运行的应用程序可以访问位于另一个域中的脚本或资源。在这种情况下,我们需要为Django服务器的域允许跨域资源共享,以便Web浏览器不会拒绝对Space中静态文件的请求。

注意:仅当您不使用带有Spaces CDN的自定义子域时,才需要执行此步骤。

首先,使用“云控制面板”导航到“空间”的“设置”页面:

在“ CORS配置”部分中,单击添加。

在“来源”下,输入通配符来源*

警告:将应用程序部署到生产环境中时,请确保将此值更改为确切的原始域(包括http://或https://协议)。将其保留为通配符源是不安全的,我们在此仅出于测试目的,因为当前不支持将源设置为http://example.com:8000(使用非标准端口)。

在“允许的方法”下,选择“获取”。

单击添加标题,然后在出现的文本框中输入Access-Control-Allow-Origin。

将访问控制最大年龄设置为600,以使我们刚创建的标头每10分钟失效一次。

点击保存选项。

从现在开始,您空间中的对象将包含适当的Access-Control-Allow-Origin响应标头,从而使现代安全的Web浏览器可以跨域获取这些文件。

测试空间静态文件传递

现在,我们将测试Django是否正确地从DigitalOcean Space提供了静态文件。

导航到您的Django应用目录:

  • cd ~/django-polls

在这里,运行collectstatic收集静态文件并将其上传到DigitalOcean Space:

  • python manage.py collectstatic

您应该看到以下输出:

Output
You have requested to collect static files at the destination location as specified in your settings. This will overwrite existing files! Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel:

输入yes,然后按Enter确认。

然后,您应该看到如下所示的输出

Output
121 static files copied.

这确认Django已成功将民意调查应用程序静态文件上传到您的Space。您可以使用Cloud Control Panel导航到Space,并检查静态目录中的文件。

接下来,我们将验证Django是否正在重写相应的URL。

启动Gunicorn服务器:

  • gunicorn --bind 0.0.0.0:8000 mysite.wsgi

在网络浏览器中,访问服务器的域名或IP地址,后跟:8000和/ admin:

http://server_domain_or_IP:8000/admin

您应该再次看到“轮询应用程序管理员身份验证”窗口,这次使用正确的样式。

现在,使用浏览器的开发人员工具检查页面内容并显示源文件的存储位置。

To do this using Google Chrome, right-click the page, and select Inspect .

您应该看到以下窗口:

在此处,单击工具栏中的源。在左侧窗格的源文件列表中,您应该在Django服务器的域下看到/ admin / login,在Space的CDN端点下看到static / admin。在static / admin中,您应该同时看到css和fonts目录。

这确认CSS样式表和字体已从您的Space的CDN中正确投放。

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

您可以通过输入deactivate禁用活动的Python虚拟环境:

  • deactivate

您的提示应恢复正常。

至此,您已成功从Django服务器上卸载了静态文件,并正在从对象存储中提供这些文件。现在,我们可以继续配置Gunicorn,使其自动作为系统服务启动。

步骤8 —为Gunicorn创建systemd套接字和服务文件

在第6步中,我们测试了Gunicorn是否可以与Django应用程序交互,但是我们应该实现一种更可靠的启动和停止应用程序服务器的方式。为此,我们将制作systemd服务和套接字文件。

Gunicorn套接字将在启动时创建,并监听连接。发生连接时,systemd将自动启动Gunicorn进程以处理连接。

首先创建并打开具有sudo权限的Gunicorn的systemd套接字文件:

  • sudo nano /etc/systemd/system/gunicorn.socket

Inside, we will create a [Unit] section to describe the socket, a [Socket] section to define the socket location, and an [Install] section to make sure the socket is created at the right time. Add the following code to the file:

/etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target

完成后保存并关闭文件。

接下来,在文本编辑器中使用sudo权限为Gunicorn创建并打开systemd服务文件。服务文件名应与套接字文件名匹配,但扩展名除外:

  • sudo nano /etc/systemd/system/gunicorn.service

从[Unit]部分开始,该部分指定元数据和相关性。我们将在此处对我们的服务进行描述,并告诉init系统仅在达到联网目标后才启动此服务。因为我们的服务依赖于套接字文件中的套接字,所以我们需要包含一个Requires指令来指示这种关系:

/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

接下来,我们将打开[服务]部分。我们将指定要运行的用户和组。由于该过程拥有所有相关文件,因此我们将授予该过程的常规用户帐户所有权。我们会将群组所有权赋予www-data群组,以便Nginx可以轻松地与Gunicorn通信。

然后,我们将映射出工作目录并指定用于启动服务的命令。在这种情况下,我们必须指定Gunicorn可执行文件的完整路径,该文件已安装在我们的虚拟环境中。我们将进程绑定到我们在/ run目录中创建的Unix套接字,以便进程可以与Nginx通信。我们将所有数据记录到标准输出,以便日记处理可以收集Gunicorn日志。我们还可以在此处指定任何可选的Gunicorn调整项,例如工作进程数。在这里,我们运行带有3个工人进程的Gunicorn。

将以下“服务”部分添加到文件中。请务必将此处列出的用户名替换为您自己的用户名:

/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/django-polls
ExecStart=/home/sammy/envs/polls/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mysite.wsgi:application

最后,我们将添加一个[安装]部分。如果我们启用该服务以在启动时启动,它将告诉systemd该服务链接到什么。我们希望该服务在常规多用户系统启动并运行时启动:

/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/django-polls
ExecStart=/home/sammy/envs/polls/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          mysite.wsgi:application

[Install]
WantedBy=multi-user.target

这样,我们的systemd服务文件就完成了。立即保存并关闭它。

现在,我们可以启动并启用Gunicorn套接字。现在将在启动时在/run/gunicorn.sock处创建套接字文件。与该套接字建立连接后,systemd将自动启动gunicorn.service来处理它:

  • sudo systemctl start gunicorn.socket
  • sudo systemctl enable gunicorn.socket

我们可以通过检查套接字文件来确认操作成功。

检查Gunicorn套接字文件

检查该进程的状态,以确定其是否成功启动:

  • sudo systemctl status gunicorn.socket

您应该看到以下输出:

Output
Failed to dump process list, ignoring: No such file or directory ● gunicorn.socket - gunicorn socket Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-03-05 19:19:16 UTC; 1h 22min ago Listen: /run/gunicorn.sock (Stream) CGroup: /system.slice/gunicorn.socket Mar 05 19:19:16 django systemd[1]: Listening on gunicorn socket.

接下来,检查/ run目录中是否存在gunicorn.sock文件:

  • file /run/gunicorn.sock
Output
/run/gunicorn.sock: socket

如果systemctl status命令指示发生错误,或者在目录中找不到gunicorn.sock文件,则表明Gunicorn套接字未正确创建。输入以下内容,查看Gunicorn套接字的日志:

  • sudo journalctl -u gunicorn.socket

在继续操作之前,请先查看您的/etc/systemd/system/gunicorn.socket文件以解决所有问题。

测试套接字激活

目前,如果您只启动了gunicorn.socket单元,由于套接字尚未收到任何连接,因此gunicorn.service将无法激活。您可以通过输入以下内容进行检查:

  • sudo systemctl status gunicorn
Output
● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead)

为了测试套接字激活机制,我们可以通过输入以下内容通过curl将连接发送到套接字:

  • curl --unix-socket /run/gunicorn.sock localhost

您应该在终端中看到应用程序的HTML输出。这表明Gunicorn已启动并能够为您的Django应用程序提供服务。您可以通过键入以下命令来验证Gunicorn服务是否正在运行:

  • sudo systemctl status gunicorn
Output
● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Tue 2019-03-05 20:43:56 UTC; 1s ago Main PID: 19074 (gunicorn) Tasks: 4 (limit: 4915) CGroup: /system.slice/gunicorn.service ├─19074 /home/sammy/envs/polls/bin/python3 /home/sammy/envs/polls/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock mysite.wsgi:application ├─19098 /home/sammy/envs/polls/bin/python3 /home/sammy/envs/polls/bin/gunicorn . . . Mar 05 20:43:56 django systemd[1]: Started gunicorn daemon. Mar 05 20:43:56 django gunicorn[19074]: [2019-03-05 20:43:56 +0000] [19074] [INFO] Starting gunicorn 19.9.0 . . . Mar 05 20:44:15 django gunicorn[19074]: - - [05/Mar/2019:20:44:15 +0000] "GET / HTTP/1.1" 301 0 "-" "curl/7.58.0"

如果curl的输出或systemctl status的输出指示发生问题,请检查日志以获取其他详细信息:

  • sudo journalctl -u gunicorn

您也可以检查/etc/systemd/system/gunicorn.service文件中的问题。如果对此文件进行更改,请确保重新加载守护程序以重新读取服务定义并重新启动Gunicorn进程:

  • sudo systemctl daemon-reload
  • sudo systemctl restart gunicorn

在继续配置Nginx服务器之前,请确保对所有问题进行故障排除。

步骤8 —配置Nginx HTTPS和Gunicorn代理传递

现在以更强大的方式设置了Gunicorn,我们需要配置Nginx来加密连接并将流量传递给Gunicorn进程。

如果您满足先决条件,并使用Let's Encrypt设置了Nginx,则Nginx的sites-available目录中应该已经有一个与您的域相对应的服务器阻止文件。如果没有,请按照如何在Ubuntu 18.04上使用“让我们加密”来保护Nginx,然后返回此步骤。

在编辑example.com服务器阻止文件之前,我们将首先删除默认的服务器阻止文件,该文件在安装Nginx之后默认情况下会推出:

  • sudo rm /etc/nginx/sites-enabled/default

现在,我们将修改example.com服务器阻止文件,以将流量传递到Gunicorn,而不是先决条件步骤中配置的默认index.html页面。

在编辑器中打开与您的域相对应的服务器阻止文件:

  • sudo nano /etc/nginx/sites-available/example.com

您应该看到类似以下的内容:

/etc/nginx/sites-available/example.com
server {

        root /var/www/example.com/html;
        index index.html index.htm index.nginx-debian.html;

        server_name example.com www.example.com;

        location / {
                try_files $uri $uri/ =404;
        }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80;
        listen [::]:80;

        server_name example.com www.example.com;
    return 404; # managed by Certbot


}

这是“如何在Ubuntu 18.04上安装Nginx”中创建的默认服务器阻止文件以及“加密”自动添加的附加内容的组合。我们将删除该文件的内容,并编写一个新配置,该配置将HTTP流量重定向到HTTPS,并将传入请求转发到在上一步中创建的Gunicorn套接字。

如果需要,可以使用cp对此文件进行备份。退出文本编辑器并创建一个名为example.com.old的备份:

  • sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.old

现在,重新打开文件并删除其内容。我们将逐步构建新的配置。

首先粘贴以下代码块,该代码块将端口80上的HTTP请求重定向到HTTPS:

/etc/nginx/sites-available/example.com
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://example.com$request_uri;
}

在这里,我们在端口80上侦听HTTP IPv4和IPv6请求,并使用example.com域发送301响应标头将请求重定向到HTTPS端口443。这还将重定向直接HTTP请求到服务器的IP地址。

在此块之后,添加以下配置代码块,用于处理example.com域的HTTPS请求:

/etc/nginx/sites-available/example.com
. . . 
server {
    listen [::]:443 ssl ipv6only=on;
    listen 443 ssl;
    server_name example.com www.example.com;

    # Let's Encrypt parameters
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location = /favicon.ico { access_log off; log_not_found off; }

    location / {
        proxy_pass         http://unix:/run/gunicorn.sock;
        proxy_redirect     off;

        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto https;
    }
}

在这里,我们首先在端口443上侦听命中example.com和www的请求。 example.com域。

接下来,我们提供默认服务器阻止文件中包含的“加密”配置,该配置指定SSL证书和私钥的位置以及一些其他安全参数。

location = /favicon.ico行指示Nginx忽略查找favicon的任何问题。

最后一个位置= /块指示Nginx将请求移交给步骤8中配置的Gunicorn套接字。此外,它添加了标头,以通知上游Django服务器已转发请求,并为它提供各种请求属性。

粘贴完这两个配置块后,最终文件应如下所示:

/etc/nginx/sites-available/example.com
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://example.com$request_uri;
}
server {
        listen [::]:443 ssl ipv6only=on;
        listen 443 ssl;
        server_name example.com www.example.com;

        # Let's Encrypt parameters
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        include /etc/letsencrypt/options-ssl-nginx.conf;
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

        location = /favicon.ico { access_log off; log_not_found off; }

        location / {
          proxy_pass         http://unix:/run/gunicorn.sock;
          proxy_redirect     off;

          proxy_set_header   Host              $http_host;
          proxy_set_header   X-Real-IP         $remote_addr;
          proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
          proxy_set_header   X-Forwarded-Proto https;
        }
}

完成后保存并关闭文件。

通过键入以下内容来测试Nginx配置是否存在语法错误:

  • sudo nginx -t

如果您的配置没有错误,请输入以下命令重新启动Nginx:

  • sudo systemctl restart nginx

现在,您应该能够访问服务器的域或IP地址以查看您的应用程序。您的浏览器应使用安全的HTTPS连接来连接到Django后端。

为了完全保护我们的Django项目,我们需要在其settings.py文件中添加几个安全参数。在编辑器中重新打开此文件:

  • nano ~/django-polls/mysite/settings.py

滚动到文件底部,并添加以下参数:

~/django-polls/mysite/settings.py
. . .

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True

这些设置告诉Django您已在服务器上启用HTTPS,并指示它使用“安全” cookie。要了解有关这些设置的更多信息,请参阅Django中的安全性的SSL / HTTPS部分。

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

最后,重新启动Gunicorn:

  • sudo systemctl restart gunicorn

至此,您已经配置了Nginx来重定向HTTP请求并将这些请求传递给Gunicorn。现在应该为您的Django项目和应用程序完全启用HTTPS。如果您遇到错误,有关Nginx和Gunicorn故障排除的讨论可能会有所帮助。

警告:如果您没有按照配置CORS标头中的说明为Spaces CDN配置自定义子域,请确保在进行以下操作之前,将原点从通配符*域更改为您的域名(本指南中为https://example.com)。您的应用可供最终用户访问。

结论

在本指南中,您将设置并配置在Ubuntu 18.04服务器上运行的可伸缩Django应用程序。可以在多台服务器之间复制此设置,以创建高度可用的体系结构。此外,可以使用Docker或其他容器运行时对这个应用及其配置进行容器化,以简化部署和扩展。然后可以将这些容器部署到Kubernetes之类的容器集群中。在即将发布的教程系列中,我们将探索如何对该Django polls应用程序进行容器化和现代化,以使其可以在Kubernetes集群中运行。

除了静态文件,您可能还希望将Django Media文件卸载到对象存储中。要了解如何执行此操作,请参阅《使用Amazon S3存储Django站点的静态文件和媒体文件》。您可能还考虑压缩静态文件,以进一步优化其向最终用户的交付。为此,您可以使用Django插件(例如Django Compressor)。