LetsEncrypt with Django and Heroku

14th February, 2019

Installing a SSL certificate using Letsencrypt can be tricky if you use Heroku as PaaS and Django. The following steps can guid you to install and update the certificate regularly.

  1.  Install Certbot locally in your computer.
    $brew install certbot  # for Mac users
  2. Initiate Certbot for manual creating of certificate.
    $sudo certbot certonly --manual

    Take care of the following fields:
    Country Code: Enter the standard two digit country code as Country Code.
    Common name: The domain (yourdomain.com) or the subdomain (www.yourdomain.com) which needs to be encrypted.

  3. There will be a call for action in the terminal after the previous step, something like below. Keep this step on hold and meanwhile do the next step before you ENTER to continue.

    Make sure your web server displays the following content at
    http://www.sonders.co/.well-known/acme-challenge/xxxxxxxxxxxx-yyyy.zzzzzzzzzzzzzzzzzzz before continuing:
    xxxxxxxxxxxx-yyyy.zzzzzzzzzzzzzzzzzzz
    If you don’t have HTTP server configured, you can run the following
    command on the target server (as root):
    mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge
    cd /tmp/certbot/public_html
    printf “%s” Gm35kFLiXnNtKT9OAOG_KPZvqMmYYAZU6DN-QRoGclg.s2I4ZV9Ne2CNtczlqXV9uw1ZdB5OSypG_cIdiuT7BwI > .well-known/acme-challenge/Gm35kFLiXnNtKT9OAOG_KPZvqMmYYAZU6DN-QRoGclg
    # run only once per server:
    $(command -v python2 || command -v python2.7 || command -v python2.6) -c \
    “import BaseHTTPServer, SimpleHTTPServer; \
    s = BaseHTTPServer.HTTPServer((‘’, 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
    s.serve_forever()”
    Press ENTER to continue

  4. Go to your Django app and make sure you get the requested string as HttpResponse from the requested URL. This step verifies your domain.

  5. Get the following files which are required by Heroku for SSL cerification at the following locations.
    Public key: /etc/letsencrypt/live/www.yourdomain.com/fullchain.pem
    Private key: /etc/letsencrypt/live/www.yourdomain.com/privkey.pem

  6. Make sure you redirect from http to http using the following customised middleware:
    class SSLRedirect:
        """Redirect the URL to SSL if option enabled."""
    
        def process_request(self, request):
            """Process request."""
            if not request.is_secure() and settings.SSL_REDIRECT:
    
                if settings.DEBUG and request.method == 'POST':
                    raise RuntimeError(
                        "Django can't perform a SSL redirect with POST data. "
                    )
    
                return HttpResponsePermanentRedirect(
                    u"https://{}{}".format(
                        request.get_host(),
                        request.get_full_path(),
                    )
                )
    ​

    and add this middleware as the very first middleware in the settings.py.

  7. If you use sitemap.xml as one of your urls, add protocol = 'https' to the Sitemap class and also any http calls for static images from CDN should be changed to https.

  8.  Change to https in the robots.txt also about the Sitemap information there.

    That's it !!