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
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.