How to Django, Certbot — HTTPS Subdomains

Derrick Gee
3 min readNov 27, 2020

This article will go through how I got subdomains to work on Django 3 with Certbot for https. It was a little finicky to get working, since I couldn’t find much info on some specific errors I was running into. Maybe I’m just not a high level search engine ninja, but I figured it out myself. My server was using nginx, but I think it shouldn’t matter if you use apache or something else. There are 3 components to get subdomains to work on Django with https: modifying domain records, using subdomains package for Django, and adding the subdomain to your certificate with certbot .

A/AAAA + CNAME Record

To open the subdomain name, we need to add an A and CNAME record to our domain. So go to your hosting service’s dashboard to create these records:

A/AAAA
Hostname: subdomain
IP Address: your_server_ip
CNAME
Hostname: *.subdomain
Aliases to: subdomain.example.com

pip install subdomains

When searching for “django subdomains”, you’ll probably come across a package called django-subdomains https://django-subdomains.readthedocs.io/en/latest/. You’ll proceed to look at the date of the post, check the source code repo, and be disappointed to see that it hasn’t been updated since nearly 2 versions of Django prior. Luckily for us, the beauty of open source means that there must be a fork it being maintained.

pip install subdomains

https://github.com/abe312/django-subdomains. As of writing this, subdomains is working with Django 3.

Setup: subdomains require you to configure the app’s settings, the urlpatterns, and database object values correctly.

# subdomains settings: project/project/settings.py
INSTALLED_APPS = [
...
"django.contrib.sites",
"subdomains",
]
# subdomains line needs to go before CommonMiddleware
MIDDLEWARE = [
...
"subdomains.middleware.SubdomainURLRoutingMiddleware",
'django.middleware.common.CommonMiddleware',
...
]
# values are app's path
ROOT_URLCONF = "project.urls"
SUBDOMAIN_URLCONFS = {
None: "project.urls",
"subdomain": "subdomain_app.urls"
}
SITE_ID = 1

Next, we need to configure the route in your urls.py of the project. Take note that there is no slash for the subdomain path.

# urlpatterns: project/project/urls.py
from django.urls import path, include
urlpatterns = [
...
path(r"subdomain", include("subdomain_app.urls")),
]

Lastly, from the setup in subdomains docs, we need to set the Site object in our database.

> python manage.py makemigrations
> python manage.py migrate
> python manage.py shell
from django.contrib.sites.models import Site
one = Site.objects.all()[0]
one.domain = 'example.com'
one.name = 'example'
one.save()

Subdomains Development and Production

I handle development and production values with an environment variable. Here is what is in my project/project/settings.py to change values depending if i’m developing or in production:

# settings.py
prj_env = "dev" # Put your env var with your favorite method
if prj_env == "dev":
DEBUG = True
ALLOWED_HOSTS = ["localhost", "subdomain.localhost"]
else:
DEBUG = False
ALLOWED_HOSTS = ["example.com", "www.example.com", "subdomain.example.com", "www.subdomain.example.com"]

This should be all we need for Django to point a subdomain request to the correct view. At this point, development on localhost should be working. Follow the next steps to get it working on production.

Certbot

If you’re in my situation where you already have a registered cert, I got good news for you. There is a flag for appending to the current certificate. Check your current certs with sudo certbot certificates , and it will be on the Domains: domain1 domain2 line. You need to run certbot -d domains with all of the current domains, append your new subdomain(s) at the end, and lastly add the --expand flag. It should look something like this:

# on prod server
> certbot -d domain1,domain2,new_subdomain --expand
# restart nginx, i'm using ubuntu here
> sudo service nginx restart

Subdomains should be working now. I’d like to hear in the comments if there is any better way to handle subdomains in Django.

--

--