Deploying Django with gunicorn and nginx

前端 未结 4 803
小蘑菇
小蘑菇 2020-12-12 08:27

This is a broad question but I\'d like to get a canonical answer. I have been trying to deploy a site using gunicorn and nginx in Django. After re

4条回答
  •  时光取名叫无心
    2020-12-12 08:52

    I am not a deployment guru but will share some of my practices for deploying Django with gevent (should be similar to gunicorn though).

    virtualenv is great for reasons I will not go into. I however found virtualenv-wrapper (docs) very useful, especially when you are working on many projects since it allows to easy switch between the different virtualenvs. This does not really apply to the deployment environment however when I do need to troubleshoot on the server using SSH, I found this very useful. Another advantage of using it is that it manages the virtualenv directory, so less manual work for you. Virtualenvs are meant to be disposable so that in case you have version issues, or any other install issues, you can just dump the env and create a new one. As the result, it is the best practice not to include any of your project code within the virtualenv. It should be kept separate.

    As for setting up multiple sites, virtualenv is pretty much the answer. You should have a separate virutalenv for each project. Just that alone can solve many issues. Then when you deploy, a different Python process will run different sites which avoids any possible conflicts between the deployments. One tool I particularly found very useful in managing multiple sites on the same server is supervisor (docs). It provides an easy interface for starting, stopping and restarting different Django instances. It is also capable of auto-restarting a process when it fails or when the computer starts-up. So for example, if some exception is raised and nothing catches it, the whole web site can go down. Supervisor will catch that and will restart the Django instance automatically. The following is a sample supervisor program (a single process) config:

    [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
    

    For Nginx, I know it can be overwhelming at first. I found Nginx book very useful. It explains all the major nginx directives.

    In my nginx install, I found the best practice is to setup only the core configs in the nginx.conf file and then I have a separate folder sites where I keep the nginx configs for each of the sites I host. Then I just include all the files from that folder in the core config file. I use the directive include sites/+*.conf;. This way it only includes the files starting with + symbol within the sites folder. That way just by the filename I can control which config files get to be loaded. So if I wish to disable a certain site, I just have to rename the config file and restart nginx. Not really sure what you meant by "symlink between site-available and sites-enabled in /etc/nginx" in your question since those are Apache named folders but they accomplish similar task as the include directive.

    As for root and alias directives, they are pretty much the same except where their root is calculated. In alias, whatever in the location in dropped, whereas in root in it not. Image that you have the following nginx config:

    location /static {
        alias /some/path/;
    }
    location /static2 {
        root /some/other/path/;
    }
    

    If the user goes to these URLs, then nginx will try to look for the files in the following places on the system:

    /static/hello/world.pdf => /some/path/hello/world.pdf
    /static2/hello/world.pdf => /some/other/path/static2/hello/world.pdf
    

    This is a simple config for nginx site:

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

    Hopefully this helps you a bit.

提交回复
热议问题