使用gunicorn和nginx部署Django

Rob*_*ith 80 deployment django nginx setup-deployment gunicorn

这是一个广泛的问题,但我想得到一个规范的答案.我一直在尝试在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

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

谢谢

Bur*_*lid 105

您认为哪种"设置"最佳?我使用了virtualenv并将我的django项目移到了这个环境中,但是我看到了另一个设置,其中有一个虚拟环境文件夹和其他项目文件夹.

virtualenv是一种隔离Python环境的方法; 因此,它在部署中没有很大的作用- 但是在开发测试期间,如果不是强烈推荐则是必需的.

您将从virtualenv获得的值是,它允许您确保为应用程序安装了正确版本的库.所以你坚持虚拟环境本身并不重要.请确保您不将其作为源代码版本控制系统的一部分包含在内.

文件系统布局并不重要.您将看到许多文章赞美目录布局的优点,甚至可以克隆的骨架项目作为起点.我觉得这更像是个人偏好而不是硬性要求.当然很高兴; 但除非你知道原因,否则它不会给你的部署过程增加任何价值 - 所以不要这样做,因为有些博客推荐它,除非它对你的场景有意义.例如 - setup.py如果您没有属于部署工作流的私有PyPi服务器,则无需创建文件.

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

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

  1. 如果您有SSL,则在端口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的配置文件背后的逻辑是什么?有很多教程使用截然不同的配置文件,我很困惑哪一个更好.例如,有些人使用"alias/path/to/static/folder"和其他人"root/path/to/static/folder".也许您可以共享首选配置文件.

您应该了解的关于nginx的第一件事是它不是像Apache或IIS这样的网络服务器.这是一个代理人.所以你会看到不同的术语,如'上游'/'下游'和多个"服务器"被定义.花点时间先阅读nginx手册.

设置nginx有很多种不同的方法; 但这里是一个回答你的问题aliasroot.root是一个绑定nginx的文档根目录("主目录")的显式指令.这是当您提供没有路径的请求时它将查看的目录http://www.example.com/

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

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

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

  • 典型的计算机至少有两个IP地址:`127.0.0.1`和​​网络分配的IP地址; 这是最低限度 - 您的机器可能有多个接口和多个IP地址.您应该配置您的网络服务器(或任何进程,真的); 听_one_ IP地址 - 这就是我明确的意思.当你绑定到"0.0.0.0"时,你告诉程序要监听所有IP地址 - 包括可能分配给你的机器的任何新地址.由于各种原因(安全性就是其中之一),这不是好的做法. (7认同)
  • 很好的答案!很多问题都澄清了。您能否详细说明一下(或添加一个示例)显式将服务器绑定到 IP 地址以及绑定 Gunicorn/uwsgi 应绑定到 0.0.0.0 的含义?不幸的是,我认为这就是我正在做的事情。谢谢! (2认同)

mik*_*725 11

我不是部署专家,但会分享我使用gevent部署Django的一些做法(尽管应该类似于gunicorn).

virtualenv因为我不会进入的原因很好.然而,我发现virtualenv-wrapper(docs)非常有用,特别是当你在许多项目上工作时,因为它允许在不同的virtualenv之间轻松切换.这并不适用于部署环境,但是当我需要使用SSH在服务器上进行故障排除时,我发现这非常有用.使用它的另一个好处是它管理virtualenv目录,因此减少了手动工作.Virtualenvs应该是一次性的,以便在遇到版本问题或任何其他安装问题时,您可以转储env并创建一个新的.因此,最好不要在virtualenv中包含任何项目代码.它应该分开.

至于设置多个站点,virtualenv几乎就是答案.你应该为每个项目都有一个单独的virutalenv.只有这一点才能解决许多问题.然后在部署时,不同的Python进程将运行不同的站点,这可以避免部署之间出现任何可能的冲突.我特别发现在同一服务器上管理多个站点非常有用的一个工具是supervisor(docs).它为启动,停止和重新启动不同的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
Run Code Online (Sandbox Code Playgroud)

对于Nginx,我知道一开始可能会让人不知所措.我发现Nginx的很有用.它解释了所有主要的nginx指令.

在我的nginx安装中,我发现最好的做法是只在nginx.conf文件中设置核心配置,然后我有一个单独的文件夹sites,我为每个托管的站点保留nginx配置.然后我只在核心配置文件中包含该文件夹中的所有文件.我使用该指令include sites/+*.conf;.这样它只包含文件夹中以+符号开头的sites文件.这样只需通过文件名我可以控制哪些配置文件被加载.因此,如果我想禁用某个站点,我只需要重命名配置文件并重新启动nginx.在你的问题中,不确定你的意思是"在/ etc/nginx中启用了站点可用和站点之间的符号链接",因为它们是Apache命名的文件夹,但它们完成了与include指令类似的任务.

至于rootalias指令,它们几乎是相同的,除非计算它们的根.在alias,无论是location在什么在下降,而在根本不是.您拥有以下nginx配置的图片:

location /static {
    alias /some/path/;
}
location /static2 {
    root /some/other/path/;
}
Run Code Online (Sandbox Code Playgroud)

如果用户转到这些URL,那么nginx将尝试在系统的以下位置查找文件:

/static/hello/world.pdf => /some/path/hello/world.pdf
/static2/hello/world.pdf => /some/other/path/static2/hello/world.pdf
Run Code Online (Sandbox Code Playgroud)

这是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这对你有所帮助.