部署Django
本章介绍构建Django应用程序的最后一个重要步骤:将其部署到生产服务器。
如果您一直关注我们正在进行的示例,那么您可能使用了runserver,这使得事情变得非常简单 - 使用runserver,您不必担心Web服务器的安装问题。 但是runserver仅用于在本地机器上进行开发,而不是暴露在公共Web上。
要部署您的Django应用程序,您需要将其绑定到像Apache这样的工业级Web服务器。 在本章中,我们将向您展示如何做到这一点 - 但首先,我们会在您上线之前为您提供一份代码库清单。
准备您的代码库进行生产
部署清单
互联网是一个敌对的环境。 在部署Django项目之前,您应该花一些时间来检查设置,并考虑安全性,性能和操作。
Django包含许多安全功能。 有些内置并始终启用。 其他是可选的,因为它们并不总是合适的,或者因为它们不便于开发。 例如,强制HTTPS可能不适合所有网站,对于本地开发来说是不切实际的。
性能优化是便利性的另一类权衡。 例如,缓存在生产中很有用,对于本地开发来说更是如此。 错误报告需求也大不相同。 以下清单包括如下设置:
- 必须为Django正确设置以提供预期的安全级别,
- 预计在每个环境中都会有所不同,
- 启用可选的安全功能,
- 启用性能优化;
- 提供错误报告。
其中许多设置都很敏感,应该视为保密。 如果您要发布项目的源代码,通常的做法是发布合适的开发设置,并使用私有设置模块进行生产。 下面介绍的一些检查可以使用检查命令的选项。 确保按照选项文档中的说明,将其与生产设置文件一起运行。
关键设置
**
**必须是一个很大的随机值,并且必须保密。
确保生产中使用的**不在其他地方使用,并避免将其提交到源代码管理。 这减少了攻击者从中获取**的向量数量。 不要在设置模块中对**进行硬编码,而应考虑从环境变量中加载该**:
import os
SECRET_KEY = os.environ['SECRET_KEY']
或者从一个文件获取:
with open('/etc/secret_key.txt') as f:
SECRET_KEY = f.read().strip()
DEBUG
您绝不能在生产中启用调试。
当我们在第1章中创建一个项目时,命令django-admin startproject创建了一个settings.py文件并将DEBUG设置为True。 Django的许多内部部分检查此设置文件并在DEBUG模式打开时更改它们的行为。
例如,如果DEBUG设置为True,那么:
所有数据库查询将作为对象django.db.connection.queries保存在内存中。 正如你可以想象的,这消耗了内存!
任何404错误将由Django的特殊404错误页面(第3章介绍)呈现,而不是返回正确的404响应。 此页面包含潜在的敏感信息,不应该
暴露于公共互联网。Django应用程序中的任何未捕获的异常(从基本的Python语法错误,数据库错误到模板语法错误)都将由您可能熟悉并喜爱的Django漂亮错误页面呈现。 此页面包含比404页面更为敏感的信息,绝不应暴露给公众。
简而言之,将DEBUG设置为True可以让Django假定只有值得信赖的开发人员正在使用您的网站。 互联网充满了不可信赖的流氓行为,当您准备部署应用程序时,您应该做的第一件事情是将DEBUG设置为False。
特殊环境的设置
ALLOWED_HOSTS
当DEBUG = False时,如果没有合适的ALLOWED_HOSTS值,Django根本无法工作。需要此设置来保护您的站点免受一些CSRF攻击。如果您使用通配符,则必须对Host HTTP标头执行自己的验证,否则确保您不容易受到此类攻击。
CACHES
如果您使用缓存,则连接参数在开发和生产中可能会有所不同。缓存服务器通常具有弱认证。确保他们只接受来自应用程序服务器的连接。如果您使用Memcached,请考虑使用缓存会话来提高性能。
DATABASES
数据库连接参数在开发和生产中可能不同。数据库密码非常敏感。你应该像SECRET_KEY一样保护它们。为了获得最大的安全性,请确保数据库服务器只接受来自应用程序服务器的连接如果您尚未为数据库设置备份,请立即执行此操作!
EMAIL_BACKEND和相关设置
如果您的网站发送电子邮件,则需要正确设置这些值。
STATIC_ROOT和STATIC_URL
静态文件由开发服务器自动提供。在生产中,您必须定义一个STATIC_ROOT目录,其中collectstatic将复制它们。
MEDIA_ROOT和MEDIA_URL
媒体文件由您的用户上传。他们不信任!确保您的Web服务器从不试图解释它们。例如,如果用户上传.php文件,则Web服务器不应执行它。现在是检查这些文件的备份策略的好时机。
HTTPS
任何允许用户登录的网站都应实施站点范围内的HTTPS,以避免明确传输访问令牌。在Django中,访问令牌包括登录名/密码,会话cookie和密码重设令牌。 (如果您通过电子邮件发送邮件,则无法保护密码重置令牌。)
保护用户帐户或管理员等敏感区域是不够的,因为相同的会话cookie用于HTTP和HTTPS。您的Web服务器必须将所有HTTP通信重定向到HTTPS,
并仅向Django发送HTTPS请求。设置完HTTPS后,启用以下设置。
CSRF_COOKIE_SECURE
将其设置为True可避免通过HTTP意外传输CSRF cookie。
SESSION_COOKIE_SECURE
将其设置为True可避免通过HTTP意外传输会话cookie。
性能优化
设置DEBUG = False会禁用一些仅在开发中有用的功能。另外,您可以调整以下设置。
CONN_MAX_AGE
连接到数据库帐户时,启用持久数据库连接可以使请求处理时间的很大一部分时间获得很好的加速。 这对网络性能有限的虚拟化主机有很大的帮助。
TEMPLATES
启用缓存的模板加载器通常会大大提高性能,因为它避免每次需要渲染时编译每个模板。 有关更多信息,请参阅模板加载器文档。
错误报告
当你将你的代码推到生产环境时,它有希望很强大,但是你不能排除意外的错误。 谢天谢地,Django可以捕获错误并相应地通知您。
日志记录
在将您的网站投入生产之前,请检查您的日志记录配置,并在收到一些流量后立即检查其是否按预期工作。
ADMINS和MANAGERS
ADMINS将通过电子邮件通知500个错误。 MANAGERS将被通知404错误。 IGNORABLE_404_URLS可以帮助过滤出虚假的报告。
通过电子邮件报告错误不能很好地扩展。 在收件箱被报告充斥之前,请考虑使用Sentry等错误监控系统。 Sentry还可以聚合日志。
自定义默认错误视图
Django包含几个HTTP错误代码的默认视图和模板。 您可能希望通过在根模板目录中创建以下模板来覆盖默认模板:404.html,500.html,403.html和400.html。 对于99%的Web应用程序,默认视图应该足够了,但如果您想对其进行自定义,请参阅这些说明,其中还包含有关默认模板的详细信息:
- http_not_found_view
- http_internal_server_error_view
- http_forbidden_view
- http_bad_request_view
使用Virtualenv
如果您将项目的Python依赖关系安装在virtualenv中,则还需要将此virtualenv的site-packages目录的路径添加到您的Python路径中。 为此,请为WSGIPythonPath指令添加一条附加路径,如果使用类UNIX系统,则用冒号(:)分隔多个路径,如果使用Windows则用分号(;)分隔多个路径。 如果目录路径的任何部分包含空格字符,则必须引用WSGIPythonPath的完整参数字符串:
WSGIPythonPath /path/to/mysite.com:/path/to/your/venv/lib/python3.X/site-packages
确保你给你的virtualenv提供了正确的路径,并用正确的Python版本(例如python3.4)替换python3.X。
使用不同的生产设置
到目前为止,在本书中,我们只处理了一个设置文件:由django-admin startproject生成的settings.py。 但是随着您准备部署,您可能会发现自己需要多个设置文件才能将开发环境与生产环境隔离。 (例如,您可能不希望在您的本地机器上测试代码更改时将DEBUG从False更改为True。)Django通过允许您使用多个设置文件使这非常简单。 如果您想将您的设置文件组织到生产和开发设置中,
您可以通过以下三种方法之一完成此操作:
设置两个完整的独立设置文件。
设置一个基本设置文件(比如说开发)和第二个(比如说production)设置文件,该文件仅从第一个文件导入并定义需要定义的任何覆盖。
只使用一个具有Python逻辑的设置文件来根据上下文更改设置。
我们一次使用一个。 首先,最基本的方法是定义两个独立的设置文件。 如果你一直在跟着,你已经有了settings.py。 现在,制作一份名为settings_production.py的副本。 (我们创建了这个名称;可以随意调用它。)在这个新文件中,更改DEBUG等。第二种方法类似,但减少冗余。 您可以将一个文件作为基本文件并创建另一个从其中导入的文件,而不是使用两个设置文件的内容大部分相似。 例如:
# settings.py
DEBUG = True
TEMPLATE_DEBUG = DEBUG
DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = 'devdb'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_PORT = ''
# ...
# settings_production.py
from settings import *
DEBUG = TEMPLATE_DEBUG = False
DATABASE_NAME = 'production'
DATABASE_USER = 'app'
DATABASE_PASSWORD = 'letmein'
在这里,settings_production.py从settings.py中导入所有内容,并重新定义特定于生产的设置。 在这种情况下,DEBUG设置为False,但我们还为生产设置设置了不同的数据库访问参数。 (后者表明你可以重新定义任何
设置,而不仅仅是像DEBUG这样的基本设置。)
最后,完成两个设置环境的最简洁的方法是使用基于环境分支的单个设置文件。 一种方法是检查当前的主机名。 例如:
# settings.py
import socket
if socket.gethostname() == 'my-laptop':
DEBUG = TEMPLATE_DEBUG = True
else:
DEBUG = TEMPLATE_DEBUG = False
# ...
在这里,我们从Python的标准库中导入套接字模块,并使用它来检查当前系统的主机名。 我们可以检查主机名以确定代码是否在生产服务器上运行。 这里的核心教训是设置文件只是Python代码。 他们可以从其他文件导入,他们可以执行任意的逻辑等。只要确保,如果你沿着这条路走下去,
设置文件中的Python代码是防弹的。 如果它引发任何异常,Django可能会崩溃。
随意将settings.py重命名为settings_dev.py或settings / dev.py或foobar.py - 只要您告诉它您正在使用的设置文件,Django就不在意。
但是,如果您重命名由django-admin startproject生成的settings.py文件,则会发现manage.py会给您一条错误消息,指出找不到设置。 这是因为它会尝试导入一个名为设置的模块。 您可以通过编辑manage.py来将设置更改为模块名称,或者使用django-admin而不是manage.py来修复此问题。 在后一种情况下,您需要将DJANGO_SETTINGS_MODULE环境变量设置为您的设置文件的Python路径(例如'mysite.settings')。
将Django部署到生产服务器
傻瓜式*部署
如果你真的想要部署一个真实的网站,那么真的只有一个明智的选择 - 找到一个明确支持Django的主机。不仅你会得到一个独立的媒体服务器(通常是Nginx),但他们也会照顾 正确设置Apache并设置一个定期重启Python进程的cron作业(以防止站点挂起)。 借助更好的主机,您还可能获得某种形式的“一键式”部署。
老实说,让自己轻松下来,并且每个月给一个知道Django的主持人支付几块钱。
使用Apache和mod_wsgi部署Django
使用Apache和mod_wsgi部署Django是一种久经考验的将Django投入生产的方法。 mod_wsgi是一个Apache模块,可以托管任何Python WSGI应用程序,包括Django。 Django将使用任何支持mod_wsgi的Apache版本。 官方的mod_wsgi文档非常棒, 这是你所有关于如何使用mod_wsgi的细节的来源。 您可能需要从安装和配置文档开始。
基本配置
一旦你安装并**了mod_wsgi,编辑你的Apache服务器的httpd.conf文件并添加以下内容。 请注意,如果您使用的是2.4以前版本的Apache,请将所有授予的Allow全部替换为Allow,并添加Order deny行,并允许在其之上。
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIScriptAlias行中的第一位是您希望为您的应用程序提供服务的基本URL路径(/表示根URL),第二位是系统中WSGI文件的位置 - 请参见下文 - 通常位于项目内部 包(在这个例子中是mysite)。 这告诉Apache使用该文件中定义的WSGI应用程序在给定URL下面提供任何请求。
WSGIPythonPath行确保您的项目包对于倒入的python路径是可用的; 换句话说,导入mysite能正常工作。 <Directory>部分只是确保Apache可以访问您的wsgi.py文件。
接下来,我们需要确保具有WSGI应用程序对象的wsgi.py存在。 从Django版本1.4开始,startproject将为您创建一个; 否则,您需要创建它。
请参阅WSGI概述以了解您应该放入此文件的默认内容,以及您可以添加到其中的其他内容。
如果多个Django站点在单个mod_wsgi进程中运行,它们都将使用首先运行的设置。 这可以通过更改来解决:
os.environ.setdefault(“DJANGO_SETTINGS_MODULE”,“{{project_name}}.settings”)
在wsgi.py中,以:
os.environ [“DJANGO_SETTINGS_MODULE”] =“{{project_name}}。settings”
或者使用mod_wsgi守护进程模式并确保每个站点都在其自己的守护进程中运行。
使用mod_wsgi守护进程模式
守护进程模式是运行mod_wsgi(在非Windows平台上)的推荐模式。 要创建所需的守护进程组并委托要在其中运行的Django实例,您需要添加适当的WSGIDaemonProcess和WSGIProcessGroup指令。
如果使用守护进程模式,上述配置所需的进一步更改是您无法使用WSGIPythonPath; 而应该使用WSGIDaemonProcess的python-path选项,例如:
WSGIDaemonProcess example.com python-path=/path/to/mysite.com:/path/to/venv/lib/pytho\
n2.7/site-packages
WSGIProcessGroup example.com
有关设置守护进程模式的详细信息,请参阅官方的mod_wsgi文档。
上一篇: python使用pil生成缩略图的方法
下一篇: NumPy库的介绍与使用教程