Skip to content

Deploy Django with WSGI

Django's primary deployment platform is WSGI, which is the standard Python interface for web servers and applications. The startproject command sets up a minimal default WSGI configuration for you that you can tweak as needed.

The application Object

The key concept of deploying with WSGI is the application callable. Web servers use this callable to communicate with your code. When you start a project, Django creates a wsgi.py file containing this exact object.

WSGI servers obtain the path to this callable from their configuration. Django's built-in development server (runserver) finds it by reading the WSGI_APPLICATION setting. By default, this is set to <project_name>.wsgi.application.

Configuring the Settings Module

When a WSGI server loads your application, Django needs to import the settings module to know how your application is defined. Django uses the DJANGO_SETTINGS_MODULE environment variable to locate this file.

If this variable is not set, the default wsgi.py file automatically sets it to mysite.settings (where mysite is your project name).

NOTE

Environment variables are process-wide. If you run multiple Django sites in the same process (which often happens with Apache and mod_wsgi), this default behavior will fail. To avoid this, use daemon mode with each site in its own process, or enforce the setting directly in your wsgi.py file using os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings".

Applying WSGI Middleware

You can apply custom WSGI middleware by wrapping the application object directly in your wsgi.py file. You can also replace the Django WSGI application with a custom WSGI application that delegates to Django later.

python
from helloworld.wsgi import HelloWorldApplication

# Wrap the default Django application
application = HelloWorldApplication(application)

Deploying with Gunicorn

Gunicorn ('Green Unicorn') is a pure-Python WSGI server for UNIX. It has no dependencies and can be installed using pip:

bash
python -m pip install gunicorn

Once installed, you can start the server by pointing it to your WSGI application. You execute the gunicorn command and pass the module path to your application object. For a project named mysite, you would run:

bash
gunicorn mysite.wsgi

By default, this command starts a process running on your local machine, listening on 127.0.0.1:8000. In a production environment, you typically bind Gunicorn to a specific IP address and port and you run it behind a reverse proxy web server like Nginx. Refer to this page for more details.

Deploying with uWSGI

uWSGI is another fast, self-healing and highly configurable WSGI server coded in pure C. It is widely used for heavy-duty deployments.

You can install it by running:

bash
# Install current stable version
python -m pip install uwsgi

# Or install LTS (long term support) version
python -m pip install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz

To run your Django project, you must tell uWSGI to use the HTTP protocol, specify a port and point it to your WSGI module. For example, the following command will serve your project on port 8000:

bash
uwsgi --http :8000 --module mysite.wsgi:application

Similar to Gunicorn, uWSGI is usually deployed behind a reverse proxy rather than facing the public internet directly.

Deploying with Apache and mod_wsgi

Deploying Django with Apache and mod_wsgi is a tried and tested way to get Django into production. mod_wsgi is an Apache module which can host any Python WSGI application, including Django. Django will work with any version of Apache which supports mod_wsgi.

Once you’ve got mod_wsgi installed and activated, edit your Apache server’s httpd.conf file and add the following lines, to route requests to your Django project:

apache
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonHome /path/to/venv
WSGIPythonPath /path/to/mysite.com

<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

The most important directive is WSGIScriptAlias. This maps a specific URL path to your wsgi.py file. In the example above, the first argument (/) tells Apache to serve your application at the root URL.

You also need to tell Apache where your Python code and dependencies live. If you use a virtual environment, you provide its path using WSGIPythonHome. You then use WSGIPythonPath to ensure your project directory is available for import. Finally, you use standard <Directory> and <Files> tags to grant Apache access to the wsgi.py file.

Using Daemon Mode

It is highly recommended to run mod_wsgi in "daemon mode" rather than the default embedded mode. This isolates your Django application in its own background process.

To use daemon mode, you replace the WSGIPythonPath directive with a WSGIDaemonProcess directive that defines your Python paths. You then link your script to this process group.

apache
WSGIDaemonProcess example.com python-home=/path/to/venv python-path=/path/to/mysite.com
WSGIProcessGroup example.com

WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py

If you encounter a UnicodeEncodeError when dealing with file uploads containing non-ASCII characters, you can fix it by adding lang='en_US.UTF-8' and locale='en_US.UTF-8' directly to your WSGIDaemonProcess directive.

apache
WSGIDaemonProcess example.com lang='en_US.UTF-8' locale='en_US.UTF-8'

Serving Static and Media Files

Django does not serve static files like images or CSS in a production environment. You must configure Apache to handle these files directly so they bypass the WSGI interface.

You can use the Alias directive to intercept requests for your static and media URLs and map them to the actual folders on your server. You must place these aliases above your WSGIScriptAlias so they take priority.

apache
Alias /robots.txt /path/to/mysite.com/static/robots.txt
Alias /favicon.ico /path/to/mysite.com/static/favicon.ico

Alias /media/ /path/to/mysite.com/media/
Alias /static/ /path/to/mysite.com/static/

<Directory /path/to/mysite.com/static>
Require all granted
</Directory>

<Directory /path/to/mysite.com/media>
Require all granted
</Directory>

WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py

To ensure the styling for the Django admin panel works correctly, you should run the collectstatic management command. This gathers all admin styles into your main static folder so Apache can serve them using the configuration above.

Authenticating Apache against Django

When using Apache and mod_wsgi, you can use Django's authentication system to restrict access to files served directly by Apache. This is very useful if you want to protect static files or other non-Django web applications using your existing Django user database.

You accomplish this using the WSGIAuthUserScript directive in your Apache configuration. You point this directive to a Python script that imports your Django environment and contains a check_password function. Apache will intercept requests to protected URLs and use your Django users to verify the provided credentials before granting access. For more details on this, refer to this Official doc.