82

这是一个广泛的问题,但我想得到一个规范的答案。我一直在尝试在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-availablesites-enabled之间创建符号链接/etc/nginx

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

谢谢

4

4 回答 4

106

您认为哪种“设置”效果最好?我使用了 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. #1 的 Nginx
  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是一个始终指向本地机器的保留地址。这就是为什么它被称为“本地主机”。它只能访问在同一系统上运行的进程。

通常你有前端服务器(上面列表中的#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;alias但这是您对vs.的问题的一个答案rootroot是绑定 nginx 的文档根目录(“主目录”)的显式指令。这是当您发出没有路径的请求时它将查看的目录http://www.example.com/

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

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

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

于 2012-10-22T04:25:46.783 回答
11

我不是部署专家,但会分享一些使用 gevent 部署 Django 的实践(不过应该类似于 gunicorn)。

virtualenv很棒,因为我不会进入。然而,我发现virtualenv-wrapper文档)非常有用,尤其是在您处理许多项目时,因为它允许在不同的 virtualenvs 之间轻松切换。这并不真正适用于部署环境,但是当我确实需要使用 SSH 在服务器上进行故障排除时,我发现这非常有用。使用它的另一个优点是它管理 virtualenv 目录,因此您的手动工作更少。Virtualenvs 是一次性的,因此如果您有版本问题或任何其他安装问题,您可以转储 env 并创建一个新的。因此,最好不要在 virtualenv 中包含任何项目代码。它应该分开存放。

至于设置多个站点,virtualenv几乎是答案。每个项目都应该有一个单独的virutalenv。仅此一项就可以解决很多问题。然后,当您部署时,不同的 Python 进程将运行不同的站点,从而避免部署之间任何可能的冲突。我发现在同一台服务器上管理多个站点时特别有用的一个工具是supervisordocs)。它为启动、停止和重新启动不同的 Django 实例提供了一个简单的界面。它还能够在进程失败或计算机启动时自动重启进程。因此,例如,如果引发了一些异常并且没有捕获它,则整个网站可能会崩溃。Supervisor 将捕捉到这一点并自动重新启动 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指令,除了计算根的位置外,它们几乎相同。in alias, in 中的任何东西都被location丢弃,而 in 它的根中没有。您具有以下 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;
    }
}

希望这对您有所帮助。

于 2012-10-22T03:53:31.997 回答
2

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

于 2013-02-08T15:21:04.477 回答
2

检查这个以获取 Django 项目所需的最小 gunicorn 和 nginx 配置。 http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/

于 2013-12-16T20:47:03.857 回答