用gunicorn和nginx部署Django

这是一个广泛的问题,但我想得到一个规范的答案。 我一直试图在Django中使用gunicornnginx来部署一个站点。 阅读了大量的教程,我已经成功,但我不能确定我所遵循的步骤是否足够好,可以毫无问题地运行网站,或者有更好的方法来做到这一点。 这种不确定性令人讨厌。

这就是为什么我要为新手寻找一个非常详细和解释清楚的答案。 我不想太多解释我所知道的和我不知道的东西,因为这可能会使答案偏离一点,其他人可能会从答案中得到较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-availablesites-enabled之间的符号链接?

  • 一些最佳实践一如既往的欢迎:-)

谢谢

你看到什么“设置”最好? 我用virtualenv和我的django项目在这个环境中移动,但是我已经看到了另一个设置,其中有一个虚拟环境和其他项目的文件夹。

virtualenv是一种隔离Python环境的方法; 因此,在部署过程中没有很大的作用 – 但是在开发testing过程中,如果不是高度推荐的话,这是一个要求。

你从virtualenv得到的价值是它可以让你确保为应用程序安装正确版本的库。 所以,你坚持虚拟环境本身并不重要。 只要确保不要将其作为源代码版本控制系统的一部分。

文件系统布局不重要。 你会看到许多文章赞美目录布局的优点,甚至可以克隆作为一个起点的骨架项目。 我觉得这比个人的要求更重要。 当然很高兴有; 但除非你知道为什么 ,否则它不会为你的部署过程增加任何价值 – 所以不要这样做,因为有些博客推荐它,除非它适合你的情况。 例如,如果您没有作为部署工作stream的一部分的私有PyPi服务器,则不需要创buildsetup.py文件。

我如何以一种允许多个站点在一台服务器上托pipe的方式进行安装?

有两件事你需要做多个网站设置:

  1. 如果您拥有SSL,则该服务器将在端口80和/或端口443上侦听公共IP。
  2. 一大堆正在运行django源代码的“进程”。

人们对#1使用nginx,因为它是一个非常快速的代理,并没有像Apache这样的综合服务器的开销。 如果你对此感到满意,你可以自由使用Apache。 没有要求“对于多个站点,使用nginx”; 您只需要一个在该端口上侦听的服务,知道如何将代理redirect到运行实际的django代码的进程。

对于#2有几种方法来启动这些过程。 gevent / uwsgi是最受欢迎的。 唯一要记住的是不要在生产中使用runserver

这些是绝对的最低要求。 通常人们添加某种进程pipe理器来控制所有的“django服务器”(#2)运行。 在这里你会看到upstartsupervisor提到。 我更喜欢主pipe,因为它不需要接pipe整个系统(不像新贵)。 但是,再次 – 这不是一个硬性要求 。 你可以完美的运行一系列的screen会话并把它们分开。 缺点是,如果您的服务器重新启动,您将不得不重新启动屏幕会话。

我个人build议:

  1. Nginx的#1
  2. 在uwsgi和gunicorn之间select – 我使用uwsgi。
  3. pipe理后端进程的主pipe 。
  4. 您所托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; 但是这里是对你的问题的aliasroot一个答案。 root是一个明确的指令,它绑定了nginx的文档根目录(“主目录”)。 这是当您提供没有像http://www.example.com/这样的path的请求时,它将查看的目录

alias意思是“将名称映射到目录”。 别名目录可能不是文档根目录的子目录。

为什么我们在/ etc / nginx中创build站点可用和站点之间的符号链接?

这是Debian独特的东西(和Debian类似的系统,如Ubuntu)。 sites-available列出了系统上所有虚拟主机/站点的configuration文件。 从sites-enabledsites-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指令类似的任务。

至于rootalias指令,它们几乎是相同的,除了根的计算。 在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/

Interesting Posts