Don’t Use SSL with Django in Development Mode
Tags: webdev, django
Published: 2020-07-12 21:24:02

Why not?

**The short answer:** Django’s built in development server is not designed to serve apps via HTTPS and it’s really hard to make it work with SSL. If you don’t need SSL for the development server, don’t bother with it.

# The Long Answer
I was building a little application to allow users to copy from one device and paste on another using Django. To make this work, I need to use Chrome’s [Clipboard API][clipboard]. I got the basic functionality working quite nicely on my development machine, so now it was time to prove that it works by showing it to my friends.

In order to do this, I had to set Django up to allow requests from hosts other than `localhost`. “No big deal,” I thought, “all I have to do is change the configuration around a little to allow outside requests, and I’m good to go.”

**FALSE**. It turns out that Chrome only exposes its Clipboard API to secure connections, which I had forgotten about when I set up the server.

I quickly generated some self-signed certificates to use for SSL and then started looking for information regarding making the Django development server handle requests via SSL. I very quickly stumbled upon this Stack Overflow question:

{% stackoverflow 7610394 %}

As you’ll notice if you follow the link, the answer says that it’s better just to run Django in a production environment if you need to test SSL. So, I followed the advice of the question, and proceeded to try and get a production grade environment set up to run my application.

The first hurdle to overcome was [channels][channels]. In order to update the user’s clipboard in real time across devices, I had to use Websockets. Channels is Django’s solution for Websockets, but unlike other web frameworks, in order to run a Django application with Channels, one has to use a completely different web server than the standard production grade Django server.

You see, there’s this Python specification called WSGI which specifies how python applications should interface with web servers like Apache and Nginx. Unfortunately, WSGI was written back in the days when two-way communication between a web server and a client wasn’t really a thing yet, and as such, WSGI servers really can’t handle bidirectional traffic.

The good people who design Python standards eventually came up with a solution, though—ASGI! Unlike WSGI, ASGI processes requests to Django applications asynchronously, enabling two-way communication between client and server—just what I was looking for.

I installed the production grade ASGI server, [daphne][daphne], which is available from PyPi. After a little bit of configuration, I succeeded in getting daphne to serve my application. Now, I just had to set up a proxy for daphne.

In the past, I had attempted to use Apache to create a proxy for a Django application, and to put it mildly, I did not enjoy the experience. After some quick googling, I found that it’s actually possible to make daphne serve requests via HTTPS, and considering my prior experience with Apache, I opted to skip a proxy for the moment, and just have daphne handle all requests itself.

After getting the server running and serving HTTPS requests, I quickly discovered I still had a problem: my static JavaScript files weren’t loading. Now, to be honest, I should have seen this one coming, because there are several articles on the Django docs describing how to serve static files in production.

To put it simply, daphne won’t serve static files, so I *still* had to set up a production grade webserver, but this time, it only had to serve static files. Considering my prior experience with Apache, I decided to go with Nginx instead. I had very little experience with Nginx before this project, so I had to learn how to configure Nginx servers on the fly. After wrestling with Nginx configs, I **FINALLY** got it to serve the files I needed. My solution was clunky. My solution was ugly. But it worked.

After hours of trying to figure out how to run a Django server with Channels in production so I could test my app from other devices, I succeeded in proving that I could copy text on my phone and paste it on my computer.

I guess what I’m trying to say is: if you don’t need SSL for testing a Django application, skip it.

[clipboard]: https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API
[channels]: https://channels.readthedocs.io/en/latest/
[daphne]: https://github.com/django/daphne