首页 文章

使用gunicorn和nginx部署Django

提问于
浏览
78

这是一个广泛的问题,但我想得到一个规范的答案 . 我一直在尝试在Django中使用gunicorn和nginx部署一个站点 . 在阅读了大量的教程后,我已经取得了成功,但我无法确定我所遵循的步骤是否足以运行一个没有问题的站点,或者可能有更好的方法来实现它 . 这种不确定性很烦人 .

这就是为什么我正在为新手寻找一个非常详细且解释清楚的答案 . 我不想过多地解释我所知道的和我不知道的事情,因为这可能会使答案有所偏差,而其他人可能会从你的答案中获益较少 . 但是,我想提到的一些事情是:

  • 你见过什么"setup"最好?我使用了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 . 也许您可以共享首选配置文件 .

  • 为什么我们在 /etc/nginx 中的 site-availablesites-enabled 之间创建一个符号链接?

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

谢谢

4 回答

  • 2

    好吧,就你在问题中提出的最佳实践而言,我无法帮助分享一个对我来说有奇迹的工具!我自己曾经在几个网站的gunicorn,nginx,supervisorD的几个配置文件中感到困惑!但我渴望以某种方式自动化整个过程,以便我可以对我的应用程序/站点进行更改并立即进行部署 . 它的名字是django-fagungis . 您可以使用Django Deployment automation here找到我的体验详情 . 我刚配置了一个fabfile.py ONCE(django-fagungis使用fabric来自动化整个过程,并在你的远程服务器上创建一个virtualenv,它可以管理单个服务器上托管的几个站点的依赖关系 . 它使用nginx,gunicorn和supervisorD来处理Django项目/站点部署)和django-fagungis从bitbucket(我用于颠覆)克隆我的最新项目并将其部署在我的远程服务器上,我只需要在本地机器的shell上输入三个命令即可! !对我来说,这已经证明是Django部署的最佳和最轻松的自由练习 .

  • 2

    检查这是否为Django项目所需的最小gunicorn和nginx配置 . http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/

  • 11

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

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

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

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

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

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

    • 如果您有SSL,则在端口80和/或端口443上侦听公共IP的服务器 .

    • 正在运行实际django源代码的一堆"processes" .

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

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

    这些是绝对最低要求 . 通常人们会添加某种流程管理器来控制所有运行的#1283916_(#2) . 在这里你会看到提到upstartsupervisor . 我更喜欢主管,因为它不需要接管整个系统(不像暴发户) . 然而,再次 - 这不是一个艰难的要求 . 你可以完美地运行一堆screen个会话并解除它们 . 缺点是,如果您的服务器重新启动,您将不得不重新启动屏幕会话 .

    我个人会建议:

    • Nginx为#1

    • 在uwsgi和gunicorn之间选择 - 我使用uwsgi .

    • supervisor用于管理后端流程 .

    • 您托管的每个应用程序的单个系统帐户(用户) .

    我建议#4的原因是隔离权限;再次,不是要求 .

    为什么有些人建议使用gunicorn_django -b 0.0.0.0:8000而其他人建议使用gunicorn_django -b 127.0.0.1:8000?我在Amazon EC2实例中对后者进行了测试,但是当前者工作没有问题时它没有工作 .

    0.0.0.0 表示"all IP addresses" - 它是一个元地址(即占位符地址) . 127.0.0.1 是始终指向本地计算机的保留地址 . 这就是为什么它被称为"localhost" . 它只能在同一系统上运行的进程访问 .

    通常,您有前端服务器(上面列表中的#1)监听公共IP地址 . 您应该将服务器显式绑定到 one IP地址 .

    但是,如果由于某种原因您使用的是DHCP或者您不知道IP地址是什么(例如,它是新配置的系统),您可以告诉nginx / apache /任何其他进程绑定到 0.0.0.0 . 这应该是 temporary stop-gap measure .

    对于 生产环境 服务器,您将拥有静态IP . 如果您有动态IP(DHCP),则可以保留 0.0.0.0 . 但是很少有你的 生产环境 机器可以使用DHCP .

    在 生产环境 中不建议将gunicorn / uwsgi绑定到此地址 . 如果将后端进程(gunicorn / uwsgi)绑定到 0.0.0.0 ,它可能会绕过您的前端代理(nginx / apache / etc)而无法访问"directly";有人可以直接请求 http://your.public.ip.address:9000/ 并直接访问您的应用程序 especially if your front-end server (nginx) and your back end process (django/uwsgi/gevent) are running on the same machine .

    如果您不想轻松运行前端代理服务器,则可以自由地执行此操作 .

    nginx配置文件背后的逻辑是什么?有很多教程使用截然不同的配置文件,我很困惑哪一个更好 . 例如,有些人使用“alias / path / to / static / folder”和其他人“root / path / to / static / folder” . 也许您可以共享首选配置文件 .

    关于nginx,你应该知道的第一件事是它像Apache或IIS一样_1283933 . 这是一个代理人 . 所以你定义了上游'/'下游'和多个"servers" . 花点时间先阅读nginx手册 .

    设置nginx有很多种不同的方法;但是这里是关于 aliasroot 的问题的一个答案 . root 是绑定nginx的文档根目录("home directory")的显式指令 . 这是当你提交没有像 http://www.example.com/ 这样的路径的请求时它会看到的目录

    alias 表示"map a name to a directory" . 别名目录可能不是文档根目录的子目录 .

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

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

  • 104

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

    virtualenv 非常好,因为我不会进入 . 然而,我发现 virtualenv-wrapperdocs)非常有用,特别是当你正在处理许多项目时,因为它允许在不同的virtualenv之间轻松切换 . 这并不适用于部署环境,但是当我需要使用SSH在服务器上进行故障排除时,我发现这非常有用 . 使用它的另一个好处是它管理virtualenv目录,因此减少了手动工作 . Virtualenvs应该是一次性的,以便在遇到版本问题或任何其他安装问题时,您可以转储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 book非常有用 . 它解释了所有主要的nginx指令 .

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

    对于 rootalias 指令,它们几乎相同,除非计算它们的根 . 在 alias 中,无论在 location 中丢弃了什么,而在根中它不是 . 您拥有以下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;
        }
    }
    

    希望这对你有所帮助 .

相关问题