Purcharsing SSL Certificate and Deploying to Django Site on Apache with mod_wsgi and mod_ssl
Published on by nick
Using SSL certificates is an essential tool for eCommerce and dealing with user data. It enables encryption of all data when it travels over the wire. This is critical when dealing with credit card numbers and user credentials.
What is good for us developers is that for not too much out-of-pocket and for very little effort, we can set up using HTTPS for almost any web site, like a blog or low traffic eCommerce site. This includes Django-powered sites. I recently built a site for a local literacy organization, Portland Literacy Launch Pad, and since this site has an authentication system, I thought it necessary to employ SSL processing. (NOTE: this site was converted to a WordPress site and no longer uses SSL for the encrypted connection.)
The first thing I did was investigate what vendors deal in these certificates. Since I recently started using Namecheap for domain registration (because 1and1 is the devil and should be abolished from this planet), I looked to them first. Sure enough, Namecheap offers a variety of SSL certificates.
Because this is primarily an informational site with a blog, a lower level SSL certificate would be sufficient. The site does allow users to sign up, but currently doesn't sell anything or process credit or debit card payments. The goal was to eventually accept payments of somekind, but for now, an entry-level SSL certificate will do just fine. I opted to go with the $9 a year Comodo PositiveSSL.
After you actually purchase the SSL certificate, there is a process by which you verify the site, set keys and configure your web server to actually use the certificate. You also must set up the Django side, by enabling secure cookies. I used this post as a guide.
These are the steps I followed. Even though there is a wealth of information on the web on this topic, I found it hard to get the whole story. Two useful posts was this one from the Geek Stuff blog and an article from the Apache wiki.
First thing you must do is generate a certificate security request (CSR). This process has many avenues, so I'll describe my method with Apache 2 and mod_wsgi and mod_ssl. Log in to your server as root, and run a command similar this (I navigated to and created these files in /etc/apache2/ssl/) and then check the file's contents:
openssl genrsa -des3 -out apache.key 2048 cat apache.key
This creates a private key. Note the 2048 at the end of the first command. This specifiies a 2048 bit encryption key. Next you will need to create the CSR and check the files were created:
openssl req -new -key /etc/apache2/ssl/apache.key -out apache.csr ls -lha apache.*
Then, finally, create the web server certificate file using the CSR file and private key for one year:
openssl x509 -req -days 365 -in apache.csr -signkey apache.key -out apache.crt cat apache.crt
I've chosen to call these files apache, but often administrators will call them the name of the server or something more unique. It doesn't really matter what you titled these; we will set the configuration that points to the path and file.
The second thing you need to do is authenticate or verify your server to the signing authority or that entity that isued your SSL certificate. This will probably differ depending on your web server and the issuer. I had to verify the CSR and activate the SSL certificate and then the issuer sent me an email with a compressed file containing the server certificate and related CRT files:
ServerCARoot.crt SSLCA.crt www_server_com.crt
Update 2015-02-18... Newer certificate bundles may come with additional files, especially if you get them from Comodo. See the following article for more information.
This post helped me find the order to concatenate.
Third, you will need to concatenate these three files together into a bundle, with the CARoot at the beginning of the file, followed by the SSL CRT and then the server CRT. Call this something like www_server_com.ca-bundle. This represents the key chain from root to server.
Fourth, you should enable HTTPS and then edit your Apache configuration file (default-ssl) found in /etc/apache2/sites-available/:
First, run this command (enables SSL on Apache):
sudo a2enmod ssl
Then, configure Apache:
SSLEngine On SSLCertificateFile /etc/apache2/ssl/www_server_com.crt SSLCertificateKeyFile /etc/apache2/ssl/server.key SSLCertificateChainFile /etc/apache2/ssl/www_server_com.ca-bundle
In general, since there are so many different Linux distribution and thus Apache default configurations, you will need to figure out how and in which files to put all this. If you start out with a standrd virtual host configuration, I would recommend simply adding the port 443 configuration to either the default-ssl or the http.conf. I recently did another HTTP to HTTPS conversion and this is the file configuration I used:
Base level config. Keep simple and clean.
NameVirtualHost and Listen statements
Port 80 configuration, WSGI, etc
Port 80/443 configuration, SSLEngine on, CRT, bundle and key files
Then, restart Apache:
service apache2 restart
Finally, to wrap up the Apache configuration, there are a couple things left to do. You should consider setting the HTTP Strict Transport Security (HSTS). This requires the headers module in Apache to be loaded. You might get errors starting your web server if this module isn't loaded. I found this post to be very helpful. Here are the steps to load the module and set the HSTS headers (command first and then setting in /etc/apache2/sites-available/default-ssl):
ln -s /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/headers.load
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
And you need to forward requests to HTTPS. You set this in your HTTP virtual host configuration file (/etc/apache2/sites-available/server). There are several ways to do this, so I will explain a simple method and leave the rest to you:
redirect permanent / https://www.server.com
This will take all external requests coming in to root (/) and forward them to your domain but with HTTPS.
The rest of the steps pertain to Django specifically. So if you are not running Django and mod-wsgi, you can restart Apache and start the testing and troubleshooting process. For Django, these settings are also necessary for session and cookie security.
# secure proxy SSL header and secure cookies SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True # session expire at browser close SESSION_EXPIRE_AT_BROWSER_CLOSE = True # wsgi scheme os.environ['wsgi.url_scheme'] = 'https'
os.environ['HTTPS'] = "on"
Then, restart Apache again:
service apache2 restart
You should then go check your server and web site and see if all this worked. If you are like me, nothing ever works the first time, so considerable troubleshooting is almost always necessary. This article is meant to be helpful but not a total and inclusive solution for all readers. Thus, if you encounter difficulty, I would do some Google searching on the topic and figure it out.