In this tutorial you will learn how to deploy a Django project to production. This tutorial will focus on deploying Django using Caprover, a self-hostable Platform-as-a-Service. The best part - you can deploy your entire project for just $5/month.

Before we get into the post, if you're interested in learning more about deploying Django, consider the JustDjango Basic Roadmap that includes a 3 hour course that goes much more in-depth on deploying Django. It covers deployment with Heroku, Digital Ocean and other deployment methods in more detail.

JustDjango Learn
Become a Professional Django Developer. Follow a structured learning syllabus for specializing in Django.

Deployment Services

There are many services you can use to deploy your Django project. I prefer using the PaaS providers such as Render, DigitalOcean and Heroku instead of IaaS provides like AWS and Azure. Using one-click apps and linking to your GitHub repository is easier and quicker than having to setup the server from scratch.

You can use the hosting provider of your choice but for this tutorial I recommend using DigitalOcean because of the Caprover Marketplace App. More on that later in the tutorial.

$100 Free Credit

In terms of pricing, you'll only need to spend $5/month to have your entire Django project hosted. But you can save yourself the cost by using my DigitalOcean referral link to get $100 of free credit. This does give me a little kick-back, but it helps enable me to make more tutorials like this.

What is Caprover?

Caprover is a free and open-source PaaS. You install it on your server and then you can manage all of your "apps" just like you do on Heroku and DigitalOcean. There are also one-click apps for Postgres, Redis and much more.

You can also read more about getting started with Caprover in their documentation.

Why use Caprover

Not only is Caprover free, it also lets you create as many apps and services as you want. To do this on another PaaS like Heroku you would pay per app.

The biggest reason for why you should use Caprover - especially if you're a beginner - is to get more experience with deploying Docker containers. Most services use a container-like deployment process and I believe it's of great benefit to learn how the deployment process works. Caprover is slightly more hands-on than deploying on Heroku or other PaaS providers.

However, there are some down-sides as well. A major one is that your apps will not have zero-downtime-deployment. During the deployment process there is a small period of time where your app could be down. Unless you have hundreds of people constantly using your app, this shouldn't be an issue.

Docker Fundamentals

Caprover uses Docker underneath the hood. Caprover creates a Docker container for each app you create. Whether that is a Postgres database or a Django project, they'll both run inside their own Docker container.

This means it's important to have a decent understanding of how Docker works. Consider learning the basics of Docker if you are not familiar with it yet.

Prerequisites

To deploy using Caprover you will need:

  1. A domain. Note that you can use CapRover without a domain,  but you won't be able to setup HTTPS.
  2. A public IP address. DigitalOcean will provide this when we setup a server.

Setting up Caprover

On DigitalOcean, create a new droplet using the Caprover marketplace app:

Select the Caprover app for the droplet

Select the cheapest plan, create a password and at the bottom of the page click the Create Droplet button.

View Caprover Login Screen

Once the droplet is created you will be able to visit http://youripaddress:3000 and see the Caprover login screen. You can find the IP address of your droplet in the detail view of your droplet. It is the ipv4 value.

The default password to login to the Caprover dashboard is captain42.

At this point you can use Caprover to deploy apps without HTTPS but I recommend completing the installation to make full use of Caprover and deploy your apps more securely.

Caprover CLI Installation

On your computer you will need to install the CLI so that you can interact with your Caprover instance.

You will need to have NodeJS installed. Once you've installed it you can then run the following command to install the Caprover CLI:

npm install -g caprover
Install the package globally

Configuring the Domain

The domain I will be using is justdjango.com. The subdomain for where Caprover will be accessible will be tutorial.justdjango.com. In this case I will add a DNS A record of *.tutorial.justdjango.com that points to the IP address of my Caprover droplet.

This is an important step. Make sure to add the DNS record in your domains' DNS management area.

Now run the CLI serversetup command:

caprover serversetup

This will prompt you to answer some questions about your Caprover instance. You will need to enter the IP address of your DigitalOcean droplet.

When you are prompted for the Captain server root domain you will enter the subdomain you created in your DNS records. In my case this will be tutorial.justdjango.com.

You will also need to create a new password for your Caprover dashboard as well as enter a valid email for SSL activation.

Lastly you will need to give your Caprover instance a name so that the CLI can identify which server to interact with. I will call mine justdjango-crm.

Access the Caprover Dashboard

Your dashboard will no longer be accessible on the IP address. You can now access it on a subdomain. In my case it will be https://captain.tutorial.justdjango.com.

Creating the Django Project

I will be deploying an existing project - a CRM built with Django. You can also watch the tutorial for how to build this project:

The finished code for the CRM project can be found in this GitHub repository. The project is already configured to use environment variables, a PostgreSQL database and also has a Django settings file that is ready for production usage.

To use the project just clone the repository:

git clone https://github.com/justdjango/getting-started-with-django.git

Inside the project, take a look at djcrm/.template.env. This file contains all of the environment variables needed to run the project:

DEBUG=True
SECRET_KEY=1234
DB_NAME=
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=
EMAIL_HOST=
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
EMAIL_PORT=
DEFAULT_FROM_EMAIL=

These are the environment variables that need to be configured in our production environment. Notice that there are database environment variables. These will be used to connect to the Postgres database.

Creating a Caprover App

We will now create our first Caprover app for the Django project. Login to your Caprover dashboard. Under Apps enter an app name (e.g django) and click Create New App.

Notice there is a checkbox for Has Persistent Data. For web apps you do not need to check this. Only apps that need to save data across sessions will require this option. The Postgres database will need this option checked - but we'll get to that later.

Once your Django app is created, click on it to view the details.

All apps are internally available to other Captain apps. Web applications are usually publicly accessible and so they also have public URLs that can access them.

The Caprover app has three main tabs:

  1. HTTP Settings
  2. App Configs
  3. Deployment
Caprover app details

Under App Configs there is a section for environment variables. Before adding all of them we will need to create a Postgres database first.

Creating a Postgres Database

Navigate back to the Apps page. Instead of creating a new app, click on the one-click apps/databases button. In the search bar, search for Postgres and then click on the PostgreSQL option.

Fill in the form with the following and then click Deploy and then Finish.

Postgres one-click app details

Once the database is deployed you will be able to connect to it via the internal host.

Click on the Postgres app to view the details:

Postgres internal name

In my case the internal host is srv-captain--postgres-db .

Add Database Environment Variables to Django App

In the Django app add the environment variables:

You can see the database environment variables have been added. The port for the Postgres database is 5432 by default.

Add database environment variables

I have left all of the email settings with a - value so that they are not empty and do not cause errors when the project is deployed. However, if you have your own SMTP credentials you can add them as environment variables now as well.

Configuring the Django App for Deployment

By default Caprover requires a Captain Definition File. This is a configuration file that tells Caprover how to deploy your project.

There are many ways to configure the Captain Definition File. I prefer to create two files:

  • The Captain Definition File
  • A Dockerfile

In the root of the project folder create a file captain-definition . Note that the file does not have an extension. In the file add the following:

{
  "schemaVersion": 2,
  "dockerfilePath": "./DockerFile"
}

In the root of the project create DockerFile also without an extension and add the following:

FROM library/python:3.8-slim-buster

RUN apt-get update \
    # dependencies for building Python packages
    && apt-get install -y build-essential \
    # psycopg2 dependencies
    && apt-get install -y libpq-dev \
    # Translations dependencies
    && apt-get install -y gettext \
    && apt-get install -y libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev shared-mime-info \
    # cleaning up unused files
    && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
    && rm -rf /var/lib/apt/lists/*

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY ./requirements.txt /requirements.txt
RUN pip install --no-cache-dir -r /requirements.txt \
    && rm -rf /requirements.txt

COPY . /usr/src/app

EXPOSE 80

CMD ["sh", "./runserver.sh"]

The DockerFile runs through a standard build process for a Django app. If you aren't familiar with Docker you can read this primer to understand more.

The runserver.sh is a bash script that will do two very important things:

  1. Collect static files
  2. Run the migrations
  3. Run the server

Create runserver.sh and add the following:

#!/bin/sh

python manage.py collectstatic --no-input
python manage.py migrate
gunicorn djcrm.wsgi --bind=0.0.0.0:80

It's important that you make the bash script executable. On MacOS and Linux you can run the following command in a terminal:

chmod +x runserver.sh

Commit the Changes

Add these changes to git by committing them.

git add .
git commit -m "Configured for caprover"

Deploy the Django Project

With everything in place we can now deploy the project. There are a few ways to do this. The easiest is to run the caprover deploy command with the CLI.

In a terminal inside the root of the project run the CLI command:

caprover deploy

You will be prompted to select the caprover machine that you are working with. Select the machine you created earlier. In my case this is justdjango-crm

Next, select the app you want to deploy. This is the Django app. The branch name to specify is main.

Any changes that have not been committed will not be pushed so make sure you have committed the new files we just created.

Enter y to start the deployment process.

Build Logs

You can see the build process take place in the Caprover dashboard under the Deployment tab.

You can also see the output in the terminal.

App Logs

If the build succeeds and the app is running you will see the app logs displayed underneath the build logs. If your deployment was successful you should see the staticfiles copied, the migrations being applied and then the server starting with gunicorn:

Successful app logs

Enable HTTPS

In the HTTP Settings tab click the Enable HTTPS button. This will take a few seconds to activate. Afterwards, navigate to your public URL and you should see the page response:

Success

Congratulations! You've now deployed your Django project. All for the cost of $5/month and a better understanding of Docker and containerised deployment.

Bonus: Linking your GitHub repository

Under the Deployment tab in Caprover, scroll down to Method 3: Deploy from Github/Bitbucket/Gitlab.

Here you will add the repository URL, the branch, username and password (or a GitHub access token):

Configure Github deployment credentials

Once you've added your credentials click Save and Update. This will create a webhook URL that you must copy and add to the repository's webhooks:

You just need to paste in the Payload URL as the webhook URL from Caprover and then specify the Content type as application/json. Click Add webhook.

Now when you push a commit to the repository it will trigger a new build on Caprover.

Bonus: Connecting a New Domain

You can add your own domain to an app on Caprover. First add an A record in your DNS for the domain and point it to the IP address of your DigitalOcean droplet.

In the HTTP settings of your app, enter the domain you want to connect and then hit Connect New Domain.

Now visit your new domain and check that the project loads. Note that you might need to add your domain to the ALLOWED_HOSTS of your Django settings.