用gunicorn和nginx部署Django
这是一个广泛的问题,但我想得到一个规范的答案。 我一直试图在Django中使用gunicorn和nginx来部署一个站点。 阅读了大量的教程,我已经成功,但我不能确定我所遵循的步骤是否足够好,可以毫无问题地运行网站,或者有更好的方法来做到这一点。 这种不确定性令人讨厌。
这就是为什么我要为新手寻找一个非常详细和解释清楚的答案。 我不想太多解释我所知道的和我不知道的东西,因为这可能会使答案偏离一点,其他人可能会从答案中得到较less的帮助。 不过,我想提到的一些事情是:
-
你看到什么“设置”最好? 我使用了virtualenv并将Django项目移到了这个环境中,但是我看到了另一个设置,其中有一个虚拟环境文件夹和其他项目的文件夹。
-
我如何以一种允许多个站点在一台服务器上托pipe的方式进行安装?
-
为什么有人build议使用
gunicorn_django -b 0.0.0.0:8000
和其他人build议gunicorn_django -b 127.0.0.1:8000
? 我在亚马逊EC2实例中testing了后者,但在前者没有问题的情况下运行不起作用。 -
nginxconfiguration文件背后的逻辑是什么? 有太多的教程使用截然不同的configuration文件,我很困惑哪一个更好。 例如,有些人使用
alias /path/to/static/folder
和其他root /path/to/static/folder
。 也许你可以分享你喜欢的configuration文件。 -
为什么我们在
/etc/nginx
创buildsite-available
和sites-enabled
之间的符号链接? -
一些最佳实践一如既往的欢迎:-)
谢谢
你看到什么“设置”最好? 我用virtualenv和我的django项目在这个环境中移动,但是我已经看到了另一个设置,其中有一个虚拟环境和其他项目的文件夹。
virtualenv是一种隔离Python环境的方法; 因此,在部署过程中没有很大的作用 – 但是在开发和testing过程中,如果不是高度推荐的话,这是一个要求。
你从virtualenv得到的价值是它可以让你确保为应用程序安装正确版本的库。 所以,你坚持虚拟环境本身并不重要。 只要确保不要将其作为源代码版本控制系统的一部分。
文件系统布局不重要。 你会看到许多文章赞美目录布局的优点,甚至可以克隆作为一个起点的骨架项目。 我觉得这比个人的要求更重要。 当然很高兴有; 但除非你知道为什么 ,否则它不会为你的部署过程增加任何价值 – 所以不要这样做,因为有些博客推荐它,除非它适合你的情况。 例如,如果您没有作为部署工作stream的一部分的私有PyPi服务器,则不需要创buildsetup.py
文件。
我如何以一种允许多个站点在一台服务器上托pipe的方式进行安装?
有两件事你需要做多个网站设置:
- 如果您拥有SSL,则该服务器将在端口80和/或端口443上侦听公共IP。
- 一大堆正在运行django源代码的“进程”。
人们对#1使用nginx,因为它是一个非常快速的代理,并没有像Apache这样的综合服务器的开销。 如果你对此感到满意,你可以自由使用Apache。 没有要求“对于多个站点,使用nginx”; 您只需要一个在该端口上侦听的服务,知道如何将代理redirect到运行实际的django代码的进程。
对于#2有几种方法来启动这些过程。 gevent / uwsgi是最受欢迎的。 唯一要记住的是不要在生产中使用runserver 。
这些是绝对的最低要求。 通常人们添加某种进程pipe理器来控制所有的“django服务器”(#2)运行。 在这里你会看到upstart
和supervisor
提到。 我更喜欢主pipe,因为它不需要接pipe整个系统(不像新贵)。 但是,再次 – 这不是一个硬性要求 。 你可以完美的运行一系列的screen
会话并把它们分开。 缺点是,如果您的服务器重新启动,您将不得不重新启动屏幕会话。
我个人build议:
- Nginx的#1
- 在uwsgi和gunicorn之间select – 我使用uwsgi。
- pipe理后端进程的主pipe 。
- 您所托pipe的每个应用程序的个人系统帐户(用户)。
我推荐#4的原因是隔离权限; 再次,不是一个要求。
为什么有人build议使用gunicorn_django -b 0.0.0.0:8000和其他人build议gunicorn_django -b 127.0.0.1:8000? 我在亚马逊EC2实例中testing了后者,但在前者没有问题的情况下运行不起作用。
0.0.0.0
表示“所有IP地址” – 它是一个元地址(即占位符地址)。 127.0.0.1
是一个总是指向本地机器的保留地址。 这就是为什么它被称为“本地主机”。 只能在同一系统上运行的进程访问。
通常,您有前端服务器(上面列表中的#1)侦听公共IP地址。 您应该明确地将服务器绑定到一个 IP地址 。
但是,如果由于某种原因,你使用的是DHCP,或者你不知道IP地址是什么(例如,它是一个新configuration的系统),你可以告诉nginx / apache /任何其他进程绑定到0.0.0.0
。 这应该是一个暂时的权宜之计 。
对于生产服务器,您将拥有一个静态IP。 如果你有一个dynamic的IP(DHCP),那么你可以留在0.0.0.0
。 尽pipe如此,您仍然可以为生产机器安装DHCP。
在生产中不推荐将gunicorn / uwsgi绑定到这个地址。 如果将后端进程(gunicorn / uwsgi)绑定到0.0.0.0
,则可能会绕过前端代理(nginx / apache / etc)而“直接”访问; 有人可以直接请求http://your.public.ip.address:9000/
直接访问你的应用程序, 特别是如果你的前端服务器(nginx)和你的后端进程(django / uwsgi / gevent)运行在同一个目录机器 。
如果您不想有运行前端代理服务器的麻烦,那么您可以自由地做到这一点。
nginxconfiguration文件背后的逻辑是什么? 有太多的教程使用截然不同的configuration文件,我很困惑哪一个更好。 例如,有些人使用“别名/path/到/静态/文件夹”和其他“根/path/到/静态/文件夹”。 也许你可以分享你喜欢的configuration文件。
首先你应该知道nginx是不是像Apache或IIS这样的web服务器 。 这是一个代理。 所以你会看到不同的术语,如“上游”/“下游”和多个“服务器”被定义。 花些时间,首先阅读nginx手册。
有很多不同的方法来设置nginx; 但是这里是对你的问题的alias
与root
一个答案。 root
是一个明确的指令,它绑定了nginx的文档根目录(“主目录”)。 这是当您提供没有像http://www.example.com/
这样的path的请求时,它将查看的目录
alias
意思是“将名称映射到目录”。 别名目录可能不是文档根目录的子目录。
为什么我们在/ etc / nginx中创build站点可用和站点之间的符号链接?
这是Debian独特的东西(和Debian类似的系统,如Ubuntu)。 sites-available
列出了系统上所有虚拟主机/站点的configuration文件。 从sites-enabled
到sites-available
sites-enabled
符号链接“激活”该站点或虚拟主机。 这是分离configuration文件并轻松启用/禁用主机的一种方法。
我不是一个部署专家,但会分享一些我的做法,用gevent部署Django(尽pipe应该类似于gunicorn)。
virtualenv
是伟大的,我不会进入的原因。 然而,我发现virtualenv-wrapper
( docs )非常有用,特别是在处理很多项目时,因为它允许在不同的virtualenvs之间轻松切换。 这实际上并不适用于部署环境,但是当我需要使用SSH进行服务器故障排除时,我发现这非常有用。 使用它的另一个好处是它pipe理着virtualenv目录,所以为你减less了手动工作。 Virtualenvs的意思是一次性的,以防万一你有版本问题,或任何其他安装问题,你可以转储env并创build一个新的。 因此,最好不要在virtualenv中包含任何项目代码。 它应该保持分开。
至于设立多个网站, virtualenv
几乎是答案。 你应该有一个单独的virutalenv每个项目。 只有这一点可以解决很多问题。 然后,在部署时,不同的Python进程将运行不同的站点,从而避免部署之间发生任何可能的冲突。 我在pipe理同一台服务器上的多个站点时特别觉得非常有用的一个工具是supervisor
( docs )。 它为启动,停止和重新启动不同的Django实例提供了一个简单的界面。 它还能够在失败或计算机启动时自动重启进程。 所以举个例子,如果引发一些例外,没有什么可以捕捉的话,那么整个网站就可能崩溃了。 主pipe会捕捉到,并会自动重新启动Django实例。 以下是示例主pipe程序(单个进程)configuration:
[program:foo] command=/path/toviertualenv/bin/python deploy.py directory=/path/where/deploy.py/is/located/ autostart=true autorestart=true redirect_stderr=True user=www
对于Nginx来说,我知道它起初可能是压倒性的。 我发现Nginx的书很有用。 它解释了所有主要的nginx指令。
在我的nginx安装中,我发现最好的做法是只设置nginx.conf
文件中的核心configuration,然后我有一个单独的文件夹sites
,我为每个托pipe的站点保留nginxconfiguration。 然后,我只是将该文件夹中的所有文件包含在核心configuration文件中。 我使用的指令include sites/+*.conf;
。 这样它只包含sites
文件夹中以+
符号开头的文件。 这种方式只是由文件名我可以控制哪些configuration文件加载。 所以,如果我想禁用某个站点,我只需要重命名configuration文件并重新启动nginx。 不太清楚你在问题中的意思是“在/ etc / nginx中的站点可用和站点之间的符号链接”,因为这些是Apache命名的文件夹,但是他们完成了与include
指令类似的任务。
至于root
和alias
指令,它们几乎是相同的,除了根的计算。 在alias
,无论在alias
location
都被丢弃了,而在根目录下却没有。 图像,你有以下的nginxconfiguration:
location /static { alias /some/path/; } location /static2 { root /some/other/path/; }
如果用户转到这些URL,那么nginx将尝试在系统的以下位置查找文件:
/static/hello/world.pdf => /some/path/hello/world.pdf /static2/hello/world.pdf => /some/other/path/static2/hello/world.pdf
这是一个简单的configurationnginx网站:
server { server_name .foodomain.com; listen 80; access_log logs/foodomain.log; gzip on; gzip_http_version 1.0; gzip_comp_level 2; gzip_proxied any; gzip_min_length 1100; gzip_buffers 16 8k; gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; # Some version of IE 6 don't handle compression well on some mime-types, so just disable for them gzip_disable "MSIE [1-6].(?!.*SV1)"; # Set a vary header so downstream proxies don't send cached gzipped content to IE6 gzip_vary on; location / { proxy_read_timeout 30s; proxy_pass http://localhost:8000; proxy_set_header Host $host; proxy_set_header User-Agent $http_user_agent; proxy_set_header X-Real-IP $remote_addr; } location /media { alias /path/to/media/; expires 1y; } location /static { autoindex on; expires 1y; alias /path/to/static/; } location /favicon.ico { alias /path/to/favicon.ico; } }
希望这可以帮助你一点。
那么,就你问的问题而言,就最佳实践而言,我不禁要分享一个为我创造奇迹的工具! 我自己曾经在几个网站上混淆了gunicorn,nginx,supervisorD的几个configuration文件! 但我渴望以某种方式自动化整个过程,以便我可以对我的应用程序/网站进行更改并立即进行部署。 它的名字是django-fagungis。 你可以在这里find关于Django Deployment自动化的细节。 我刚刚configuration了一个fabfile.py ONCE(django-fagungis使用结构来自动化整个过程,并在远程服务器上创build一个virtualenv, 非常方便的pipe理一个服务器上托pipe的多个站点的依赖关系,它使用nginx,gunicorn和supervisorD处理Django项目/站点部署)和django-fagungis克隆我的最新项目从bitbucket(我用于颠覆),并将其部署在我的远程服务器上,我只需要input三个命令在我的本地机器的shell, ! 对我来说,这已经成为Django部署的最佳和无忧的练习。
检查Django项目所需的最小gunicorn和nginxconfiguration。 http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/