使用gunicorn和nginx部署Django


81

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

这就是为什么我要为新手寻找一个非常详细且经过充分解释的答案。我不想过多地解释我所知道的和我所不知道的,因为这可能会使答案有些偏颇,而其他人可能会从您的答案中受益较少。但是,我想看到的是:

  • 您认为哪种“设置”效果最好?我使用了virtualenv并将我的Django项目移至该环境中,但是我看到了另一种设置,其中有一个用于虚拟环境的文件夹,另一个用于项目的文件夹。

  • 如何设置方式以允许将多个站点托管在单个服务器中?

  • 为什么有人建议使用gunicorn_django -b 0.0.0.0:8000而另一些建议gunicorn_django -b 127.0.0.1:8000呢?我在Amazon EC2实例中测试了后者,但是前者没有问题时却无法正常工作。

  • Nginx的配置文件背后的逻辑是什么?有太多使用完全不同的配置文件的教程,我困惑于哪个更好。例如,有些人使用alias /path/to/static/folder而另一些人root /path/to/static/folder。也许您可以共享您的首选配置文件。

  • 为什么我们之间创建一个符号链接site-available,并sites-enabled/etc/nginx

  • 一如既往地欢迎一些最佳做法:-)

谢谢


您能在git上发布有关这些nginx和gunicorn / uwsgi的示例吗?它将对像我这样的新学习者更有用。
湿婆

@Shiva实际上,miki725的答案包含一个非常完整的配置文件示例。如果您想对nginx发生的事情进行彻底的介绍,我建议您< ahref=" amazon.com/Nginx-HTTP-Server-Cl%C3%A9ment-Nedelcu/dp/…本书</ a>。该gunicorn整合是非常简单的它概括<a href=" docs.djangoproject.com/en/dev/howto/deployment/wsgi/gunicorn/...>
罗伯特·史密斯

Answers:


106

您认为哪种“设置”效果最好?我使用了virtualenv并将django项目移动到该环境中,但是我看到了另一种设置,其中有一个用于虚拟环境的文件夹,另一个用于项目的文件夹。

virtualenv是隔离Python环境的一种方法。因此,它在部署中没有很大的作用-但是在开发测试过程中,如果不强烈建议,则是必需的。

您可以从virtualenv获得的价值在于,它可以确保为应用程序安装了正确的库版本。因此,将虚拟环境本身粘贴在什么位置都没有关系。只要确保您没有将其包含在源代码版本控制系统中即可。

文件系统布局并不重要。您将看到许多文章,这些文章都赞扬了目录布局的优点,甚至可以克隆可以作为起点的框架项目。我觉得这更多是个人喜好而不是硬性要求。当然很高兴;但是除非您知道为什么,否则它不会为您的部署过程增加任何价值-请勿这样做,因为有些博客建议您这样做,除非对您的情况有意义。例如-setup.py如果您的部署工作流程中没有私有PyPi服务器,则无需创建文件。

如何以允许将多个站点托管在单个服务器中的方式进行设置?

您需要做两件事来进行多个站点设置:

  1. 正在使用端口80和/或端口443上的公用IP侦听的服务器。
  2. 一堆正在运行实际django源代码的“进程”。

人们将nginx用于#1,因为它的代理速度非常快,并且没有像Apache这样的综合服务器带来的开销。如果您愿意,可以自由使用Apache。没有要求“对于多个站点,请使用nginx”;您只需要在该端口上侦听的服务即可,该服务知道如何重定向(代理)到运行实际django代码的进程。

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

这些是最低要求。通常,人们添加某种流程管理器来控制所有“ django服务器”(#2)的运行。在这里,您将看到upstartsupervisor提及。我更喜欢主管,因为它不需要接管整个系统(不同于新贵)。但是,这又不是硬性要求。您可以完美地运行一系列screen会话并将它们分离。缺点是,如果服务器重新启动,则必须重新启动屏幕会话。

我个人建议:

  1. Nginx为#1
  2. 在uwsgi和gunicorn之间选择-我使用uwsgi。
  3. 管理后端流程的主管
  4. 您所托管的每个应用程序的单独的系统帐户(用户)。

我建议#4的原因是为了隔离权限。同样,这不是必需的。

为什么有些人建议使用gunicorn_django -b 0.0.0.0:8000,而另一些人建议使用gunicorn_django -b 127.0.0.1:8000?我在Amazon EC2实例中测试了后者,但是前者没有问题时却无法正常工作。

0.0.0.0表示“所有IP地址”-它是一个元地址(即占位符地址)。127.0.0.1是始终指向本地计算机的保留地址。这就是为什么将其称为“ localhost”。仅在同一系统上运行的进程才可以访问。

通常,您让前端服务器(上面列表中的#1)监听公共IP地址。您应该将服务器明确绑定到一个IP地址

但是,如果由于某种原因使用了DHCP或不知道IP地址是什么(例如,它是新配置的系统),则可以告诉nginx / apache /任何其他进程绑定到0.0.0.0这应该是暂时的权宜之计

对于生产服务器,您将拥有一个静态IP。如果您有动态IP(DHCP),则可以保留0.0.0.0。但是,为生产计算机配备DHCP的情况很少见。

在生产中不建议将gunicorn / uwsgi绑定到此地址。如果将后端进程(gunicorn / uwsgi)绑定到0.0.0.0,则可以“直接”访问它,而绕过前端代理(nginx / apache / etc);有人可能只是http://your.public.ip.address:9000/直接请求并访问您的应用程序,特别是如果您的前端服务器(nginx)和后端进程(django / uwsgi / gevent)在同一台计算机上运行

如果您不想运行前端代理服务器的麻烦,则可以自由地这样做。

Nginx的配置文件背后的逻辑是什么?有太多使用完全不同的配置文件的教程,我困惑于哪个更好。例如,有些人使用“别名/ path / to / static / folder”,其他人使用“ root / path / to / static / folder”。也许您可以共享您的首选配置文件。

关于nginx,您应该了解的第一件事是它不是像Apache或IIS这样的Web服务器。它是代理。因此,您将看到不同的术语,例如“上游” /“下游”,并且定义了多个“服务器”。请花一些时间并首先阅读nginx手册。

设置nginx的方法有很多。但这是您对aliasvs.问题的一个答案rootroot是绑定nginx的文档根目录(“主目录”)的显式指令。这是您在没有路径的情况下发出请求时要查看的目录http://www.example.com/

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

为什么要在/ etc / nginx中的可用站点和启用站点之间创建符号链接?

这是debian(和像ubuntu这样的debian之类的系统)所特有的。 sites-available列出系统上所有虚拟主机/站点的配置文件。从sites-enabled到的符号链接sites-available“激活”该站点或虚拟主机。这是分离配置文件并轻松启用/禁用主机的一种方法。


1
好答案!澄清了很多问题。您能否详细说明(或添加一个示例)将服务器显式绑定到IP地址以及将gunicorn / uwsgi绑定到0.0.0.0的含义?不幸的是,我认为这就是我正在做的。谢谢!
罗伯·史密斯

7
一台典型的计算机将至少具有两个IP地址:127.0.0.1一个由网络分配给它的IP地址;这是最低要求-您的计算机可能具有多个接口和多个IP地址。您应该配置您的Web服务器(或任何进程)。侦听一个IP地址-这就是我明确的意思。绑定时0.0.0.0,您要告诉程序监听所有IP地址,包括可能分配给计算机的任何新IP地址。由于各种原因(安全性就是其中之一),这不是一个好习惯。
Burhan Khalid 2012年

得到它了。我已经正确配置了Gunicorn。非常感谢你!
罗伯·史密斯

nginx可以提供静态内容。
Marcin 2013年

服务器如何知道我们在哪个文件中配置了服务器地址/etc/nginx/sites-enabled
Shiva

11

我不是部署专家,但将分享我使用gevent部署Django的一些做法(尽管应该与gunicorn相似)。

virtualenv因为我不愿讨论的原因而很棒。但是,我发现virtualenv-wrapperdocs)非常有用,尤其是当您在许多项目上工作时,因为它可以轻松地在不同的virtualenv之间切换。这确实不适用于部署环境,但是当我确实需要使用SSH在服务器上进行故障排除时,我发现这非常有用。使用它的另一个优点是它管理virtualenv目录,因此您的手动工作较少。Virtualenvs是可抛弃的,因此,如果您遇到版本问题或任何其他安装问题,则可以转储env并创建一个新的env。因此,最佳实践是不要在virtualenv中包含任何项目代码。应该分开存放。

至于设置多个站点,virtualenv几乎就是答案。对于每个项目,您应该有一个单独的virutalenv。仅此一项就可以解决许多问题。然后,在部署时,不同的Python进程将运行不同的站点,从而避免了部署之间的任何可能的冲突。我特别发现在管理同一服务器上的多个站点时非常有用的一种工具是supervisordocs)。它提供了一个简单的界面,用于启动,停止和重新启动不同的Django实例。它还可以在失败或计算机启动时自动重新启动进程。因此,例如,如果引发了某种异常却没有发现任何异常,则整个网站可能会崩溃。主管将捕获该错误,并将自动重新启动Django实例。以下是示例主管程序(单个进程)配置:

[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文件中设置核心配置,然后有一个单独的文件夹sites,在该文件夹中存放我托管的每个站点的nginx配置。然后,我只将该文件夹中的所有文件都包含在核心配置文件中。我使用指令include sites/+*.conf;。这样,它仅在文件夹中包括以+符号开头的sites文件。这样,仅通过文件名,我就可以控制要加载的配置文件。因此,如果我想禁用某个站点,则只需重命名配置文件并重新启动nginx。不太确定您在问题中所说的“ / etc / nginx中站点可用和站点启用之间的符号链接”是什么意思,因为它们是Apache命名的文件夹,但它们完成与include指令相似的任务。

至于rootalias指令,除了根的计算位置外,它们几乎相同。在中alias,无论inlocation中的下落是什么,而在root中的则不是。具有以下nginx配置的图像:

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

这是nginx站点的简单配置:

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;
    }
}

希望这对您有所帮助。


实际上,您的回答很有帮助!主管听起来很棒,这是博主之间似乎达成共识的少数事情之一。有关虚拟环境及其包装的好建议。我很想将virtualenv-wrapper添加到组合中,但是我不想不必要地增加此问题的复杂性。至于站点可用和站点启用,nginx包含这些目录。您在哪里为Nginx创建配置文件?在您的Django项目中?
罗伯·史密斯

我个人将它们放在nginx config文件夹中。就我而言/usr/local/nginx/config/sites。但是不知道这是正确的方法还是更好的方法。之所以将它们保留在其中,是因为如果将其移出,则必须以某种方式将其包含在nginx中,方法是通过手动包含include指令或进行符号链接。无论哪种情况,都是手工操作,因此我将其保留在主配置位置。
miki725

我正在阅读您推荐的书:-)很棒,而且您可能还记得,/ sites / *。conf是一种建议的实现方式。无论如何,谢谢您的回答。
罗伯·史密斯

别客气。关于本书的一小部分虽然不是很有用,但是如何将Django与nginx结合使用。本书建议使用fastcgi,这并不像使用代理通过那样整齐。因此,您可以跳过第6章
。– miki725

我刚看完书。这很棒。我实际上阅读了第6章,因为我想知道hoy fastcgi的工作原理,但是您是对的……它不是很有用。谢谢!
罗伯·史密斯 Robert Smith)

2

好吧,就您在问题中提出的最佳实践而言,从字面上看,我不禁分享一个对我有用的工具!我自己曾经在几个站点的gunicorn,nginx,supervisorD的几个配置文件中感到困惑!但是我渴望以某种方式使整个过程自动化,以便可以更改我的应用程序/站点并立即进行部署。它的名字叫django-fagungis。您可以在此处找到有关Django部署自动化的经验的详细信息。我刚刚配置了一个fabfile.py ONCE(django-fagungis使用Fabric来自动化整个过程,并在远程服务器中创建一个virtualenv,这非常方便管理单个服务器上托管的多个站点的依存关​​系。它使用nginx,gunicorn和supervisorD来处理Django项目/站点部署),而django-fagungis从bitbucket克隆了我的最新项目(我将其用于Subversion)并将其部署在远程服务器上,而我只需要在shell上输入三个命令我的本地机器,它!对我来说,这对于Django部署来说是最好的,而且很方便。


谢谢!。我会看一下。
罗伯·史密斯

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.