38

There are 3 ways to run a django application with gunicorn:

  1. Standard gunicorn + wsgi (ref django doc)

    gunicorn project.wsgi:application

  2. Using gunicorn django integration (ref gunicorn doc and django doc):

    python manage.py run_gunicorn

  3. Using gunicorn_django command (ref gunicorn doc)

    gunicorn_django [OPTIONS] [SETTINGS_PATH]

Django's documentation suggests using 1., which is not even listed as an option on Gunicorn documentation.

Is there any best practice on the best way to run a django app with gunicorn, and what are the foreseable advantages/disadvantages of these different solutions?

Taking a glimpse at gunicorn's code it looks like they pretty much all do the same: 2. seems to be creating a wsgi app using django's internals, and 3. uses 2.

If that's the case, I wouldn't even understand what's the reason for not simply using "1." all the time, especially since a wsgi.py file is autocreated for you since django 1.4; if that's true maybe simply a documentation improvement should be suggested...

Also, best practice for gunicorn settings with django would be great. Using 1., does it make sense to set some defaults in the wsgi file and avoid additional settings?

References:

  1. Should I use django-gunicorn integration or wsgi? only concerns choices 1. and 3., there's no hint for the settings and the answer gives no rationale
  2. Deploying Django with gunicorn and nginx give some broader information but is not strictly related nor answer this question
  3. Django Gunicorn wsgi about version "4", which is launching gunicorn -c configfile and configfile will point to django_settings to django
  4. Django WSGI and Gunicorn is just a bit confusing :) mixing up 1. and 3. Of course wsgi.py is used only with 1.
Community
  • 1
  • 1
Stefano
  • 18,083
  • 13
  • 64
  • 79
  • 1
    I have published 70+ django best practices to scale django to millions of users. It also includes gunicorn and wsgi tuning insights. https://digiqt.com/blog/django-best-practices-for-scalable-apps.html – Hitul May 23 '21 at 04:58

3 Answers3

43

After checking out I'd say that the best way is using gunicorn + wsgi

$ gunicorn project.wsgi:application

It's now both confirmed in gunicorn docs: if you run Django 1.4 or newer, it’s highly recommended to simply run your application with the WSGI interface using the gunicorn command and django as linked above.

It also avoids adding gunicorn as installed app, which means it's not a requirement to install gunicorn to test your app which might be useful from time to time.

About Settings

The Django settings file to be used can be passed through an ENV variable, or customized in the wsgi.py file. I sometimes create several wsgi.py files if I have multiple settings (eg. multiple websites) that have to run from the same project - See Django Doc for more info.

A one-liner solution that does not require any new file from Carl's comment:

DJANGO_SETTINGS_MODULE=project.settings.prod gunicorn project.wsgi:application

sounds like a nicer way (though I'll probably end up writing it in some shell commands to make it easy to "remember").

Gunicorn settings can be passed as -c settings_file, but I'm exploring other ways and will try to update this answer if I find any. Using environment variables seems a workaroud, but only for limited cases

In particular it would be nice to get/share some settings between django and gunicorn; gunicorn documentation says:

Currently, only Paster applications have access to framework specific settings. If you have ideas for providing settings to WSGI applications or pulling information from Django’s settings.py feel free to open an issue to let us know.

(Update: haven't found any smarter way, but after all env variables are enough for my most-common cases).

Community
  • 1
  • 1
Stefano
  • 18,083
  • 13
  • 64
  • 79
  • Yes, this is the best way. The reason the other modes exist is that gunicorn was created before the Django default project template included a proper WSGI entrypoint, so the gunicorn devs could not make the assumption that their Django users would have one. – Carl Meyer Jan 27 '14 at 23:45
  • I'm not entirely clear what you are asking about settings - I think it might be best if you ask a separate question about that, with some clear examples of what kinds of settings you are thinking of. – Carl Meyer Jan 27 '14 at 23:50
  • @CarlMeyer I'm speaking about django settings and gunicorn settings (though I admit it wasn't very clear and I tried being more explicit). It's hard to speak about launching a django instance without being able to reproduce the customizable `./manage.py run_gunicorn --settings=SETTINGS`. In particular, I use different settings when I have a project that runs several instances (eg. multiple websites on django-cms). My current solution for django settings is multiplying the WSGI files (or settings the ENV variable). – Stefano Jan 28 '14 at 01:05
  • 6
    Just set the environment variable DJANGO_SETTINGS_MODULE, that's by far the simplest way. I have never in my life used the `--settings` argument to `manage.py`, I'm not even sure it should exist. You can even set the env var in a single command line if you want, e.g. `DJANGO_SETTINGS_MODULE=project.settings.prod gunicorn project.wsgi:application` – Carl Meyer Jan 28 '14 at 17:24
4

I guess using run_gunicorn is the way to go, it's also the simplest way to use it.

It's basically the same as usign gunicorn project.wsgi:application but needs gunicorn to be added to INSTALLED_APPS so that django recognizes the run_gunicorn command, therefore it's probably not the default way...

Using gunicorn_django is more or less deprecated, as the documentation also states here...

Bernhard Vallant
  • 49,468
  • 20
  • 120
  • 148
  • 1
    well according to that doc `gunicorn djangoapp.wsgi:application` is the way to go, not even `run_gunicorn`; still I was trying to understand why 3 modes, a weird note in the documentation about the /suggested/ way, and what's the best practice for configuration (as I can imagine fitting part of it inside the `wsgi.py` file)... thanks! – Stefano Jun 01 '13 at 17:12
  • 1
    The `run_gunicorn` command now contains a warning about being deprecated and to be removed in R21. – Tuttle Mar 26 '16 at 14:33
  • This is no longer the way to go, but I'm glad this answer exists, it helped me understand why a `gunicorn` entry was added to `INSTALLED_APPS` in 2014, and confirmed that I can now get rid of it. – Bruno A. Jul 09 '19 at 10:29
0

Found a solution that works both for manage.py (on local machine) and with gunicorn

create a file that has all the evniroment stuff

# mysite/settings/set_env.py

import os

_environment = os.getenv('environment', None)
if _environment == "production":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.production")
elif _environment == "development":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.development")
else:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings.local")

and import this file in your manage.py and wsgi.py files, no need to change anything else in gunicorn execution

Yarh
  • 895
  • 7
  • 15