Article by Ari Birnbaum @ceiphr
Technical writer featured in DigitalOcean and Medium Programming.

Why the update

This website is built with Django, a compelling framework that is known to be the basis for sites like Instagram and Pinterest. My site merely showed a couple of images and a contact form that sent unauthenticated emails to my inbox. That didn’t feel like a good use for Django, especially if I’m hosting this site for a monthly fee. So below are all the new features and tweaks I’ve made to this site to better leverage the power of Django.

The Blog

This blog has full markdown support with syntax highlighting thanks to mistune, pygments, and this wonderful tutorial. Below you will see examples of the markdown and syntax highlighting with a Monokai theme (because it’s the best). And if you scroll to the bottom of this page there might be recommendations for the latest articles I’ve posted.

Improved Performance

I’ve also been using Google’s to better adhere to web standards and generally improve this site’s performance.

All images are now properly sized to avoid using extra bandwidth. JazzBand’s Sorl-Thumbnail Django app allowed me to convert image formats and resize them to better function on mobile devices. But there was one problem, Apple (of course).

Safari doesn’t support modern image formats, like Google’s WebP, so every image in each Django template had to be rewritten in order for Apple devices to use, the more widely supported, JPEG:

  <!-- WebP image -->
  {% thumbnail image_name "120x120" format="WEBP" as webp %}
  <source data-srcset="{{ webp.url }}" type="image/webp" />
  {% endthumbnail %}
  <!-- JPEG fallback image -->
  {% thumbnail image_name "120x120" format="JPEG" as jpeg %}
  <source data-srcset="{{ jpeg.url }}" type="image/jpeg" />
  {% endthumbnail %}
  <img />

Besides that hiccup in development, this site is clearly the fasted one I’ve built to date with Lighthouse giving this site’s front page a 97/100 for performance.

Better SEO

Search Engine Optimization allows my site to appear higher in Google search based on the way information is organized and given to web crawlers.

In order for web crawlers to establish what pages to look at they visit the sitemap.xml for each given site (if it’s available). A sitemap shows all the indexed pages on a given website. The sitemap I was initially using on this project was static because pages didn’t change, only the contents did (e.g. adding new projects/skills/events). Once the blog was added, that system needed to be revamped.

Django comes with a sitemap framework by default where I make a basic file and have it talk to to generate a sitemap based on article entries and static pages. Django does a really great job of making this simple and easy to implement since below is all the code I had to write for the sitemap generator:

from django.urls import reverse
from django.contrib.sitemaps import Sitemap
from database.models import Article

# Static pages
class StaticViewSitemap(Sitemap):
    changefreq = 'daily'
    priority = 1.0

    def items(self):
        return ['FrontPage', 'Projects', 'Blog', 'Events', 'Skills', 'Contact']

    def location(self, item):
        return reverse(item)

# Blog articles
class BlogSitemap(Sitemap):
    changefreq = 'never'
    priority = 0.5

    def items(self):
        return Article.objects.all()

    def lastmod(self, obj):
        return obj.modified

Metadata has also been reworked. To help crawlers and social media sites properly display blog posts the base template needed to be updated to support article metadata. This means that when an article is posted on social media, instead of a plain link, the user gets a rich content widget that displays an article’s title, summary and header image. Anything I publish should have a higher average search ranking on Google thanks to thorough metadata for each post and static page.

Security Hardening

A website is nothing if it’s not secure. I don’t want my site vandalized nor do I want people getting access to private information such as API keys. So I’ve tried to maintain a high level of security when it comes to this site and comply with standards pertaining to server and website security.

The Server

We’re using Certbot with Let’s Encrypt for SSL, so your connection to this site is encrypted. My production NGINX is configured with SSL stapling, session caching (50 minutes) and HSTS (1 year) enabled. All secret and API keys are kept on the production server and are git-ignored, so I don’t accidently publish them to this project’s Gitlab repository. The server also requires an SSH key to log in and has brute force protection which blocks multiple connection attempts.

Qualys SSL Labs gives this site an A+ which means we’re safe for now.

The Django Project

You won’t find the admin panel for this site because the URL is a 128 character hash. But if you defy the odds and somehow manage to do that, I’m using TOTP (Django-OTP) and a 128 character password, so go away. And of course my passwords are salted and hashed thanks to Django’s account management system.

Instead of running Postfix for my email system I’ve integrated this site with SendGrid specifically because they authenticate domains and their web API can be used seamlessly with Django. Now if you use this site’s contact form it will send you and me a copy of the message via [email protected]. Emails are therefore handled securely by SendGrid who also authenticates my mail domain. The headers for both emails also contain a reply_to attribute that allows me to reply directly to your email address and for you to directly reply to me, so we don’t bother our good bot, noreply.

Complying with Standards

I’m slowly moving my naming scheme for python variables over to PEP8 and my classes/IDs over to BEM, but renaming anything is annoying and generally leads to many bugs, so I will take my sweet time.

Starting with this release I will be basing my change logs off Keep a Changelog and adhering to semantic versioning for denoting changes to all of my side projects over at Below is a change log of all the significant changes made to this site over the past two weeks using those standards.

Wrap up

This update makes this site faster and more robust than previous versions while also displaying more dynamic content. Check out the full changelog. In the coming weeks I will be drafting posts for this site that I hope will act as useful tutorials and resources for web development, server management, online privacy and security.

Thank you for reading my first post.

This article is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
Found an error in this article? Email me [email protected] or tweet at me @ceiphr.

How To Display Data from the DigitalOcean API with Django

December 20, 2019

This tutorial is for leveraging DigitalOcean's API with Django.

A Crash Course in Django

June 28, 2019

This crash course is a quick way to get started making a basic Django website without going in-depth about the underlying concepts.