How to Deploy Django to AWS with Docker: Step-by-Step Guide for Scalable Apps

Why use Docker and AWS

We all heard this expression many times when an application doesn't work in the production environment, "But it works on my machine". One of the main reasons we fall into this situation is that our development environment is different from our staging or production environment. One way to overcome this situation, is to containerize our application using Docker to ensure that development, staging, and production environments match exactly. By doing so, we can also save a lot of DevOps time on preparing each environment, installing packages, libraries, etc.

Now, pairing Docker with AWS can give even more benefits:

  • Scalability
  • Secure Infrastructure and Access Control
  • Automating the deployment and spinning-up process

AWS provides different ways to run our dockerized application:

  • AWS ECS (Elastic Container Service): This is a fully managed container orchestration; AWS takes care of EC2 provisioning, load balancing, and health checks.
  • AWS Fargate:  This is a Serverless solution for our containers. No EC2 gets provisioned and you pay only resources (vCPU and Memory) you use.
  • AWS Elastic Beanstalk: This is easier to learn solution to deploy your application. Elastic Beanstalk adds an abstraction on top of the platform configuration to make it easier for you to deploy your application without going through a complex setup. It also includes tools for status and health checks.

We are going to use AWS Elastic Beanstalk for this article. This is an ideal solution if you want to deploy your application quickly with low ops effort.

Prerequisites

Before we dive into building and deploying our application make sure you have:

  • An AWS account with enough permissions for Elastic Beanstalk and Elastic Container Registry to store our Docker images.
  • AWS CLI
  • Docker and Docker Compose, follow Docker instructions for installation 
  • Python 3.13.4 and Djanog 5.2.2
  • Python virtual environment

Preparing Your Development Environment

Let's start by installing the necessary packages and setting up our project:

Check if Elastic Beanstalk is installed successfully by running eb --version

Now let's create a requirements file to save all installed packages and their versions and save it in the root of the project:

pip freeze > requirements.txt

Next let's add .gitignore to our project and add the following content to it:

Initialize git and commit the project:

Building Task Manager App

Create Django Project

Run the following command to create a new Django project:

django-admin startproject task_manager .

This generates:

  • manage.py
  • task_manager/ folder with settings.pyurls.py, etc.

Now scaffold the tasks app by running the following command in the task_manager project folder:

python manage.py startapp tasks

You should now see a new tasks/ folder alongside manage.py.

Register Your “tasks” App

Open task_manager/settings.py and add tasks, to the INSTALLED_APPS list.

Whitelist Hosts

In the settings.py file and look for ALLOWED_HOSTS and add * to it. This is not a secure practice, and we are doing this for our development. When you have your actual URL, replace this with your app URL to keep it secure

ALLOWED_HOSTS= ['*']

Define Your Task Model  

Let’s create a simple model to represent a task in tasks/models.py.

Open tasks/models.py and replace its contents with the following:

Save the file and run Django migration

Now lets register it in admin. Replace the contents of tasks/admin.py with the following:

Create a superuser and run the dev server:

Visit http://127.0.0.1:8000 and login to http://127.0.0.1:8000/admin to confirm we are all set

Add CRUD Views

Let's use Django’s built-in generic class-based views for a quick CRUD interface.

Replace the content of tasks/views.py with the following:

We built views for listing, creating, updating, viewing and deleting tasks.

Wire up URLs

Let's wire these views to URLs and create minimal templates so you can test them. 

Create tasks/urls.py file with the following content:

Add it to the project main URLs task_manager/urls.py by replacing the content with the following:

Add Templates

In the project root django-docker-eb create a folder called templates and add the following files to it

base.html

Now create a new folder called tasks under templates and add the following files to it

task_list.html

task_detail.html

task_form.html

task_confirm_delete.html

Now let's make sure Django can find our templates. Open the settings.py file and look for TEMPLATES array and add the [BASE_DIR / 'templates'] to the DIRS key 

To test our templates run the Django server if its not running already 

python manage.py runserver

and visit the http://127.0.0.1:8000/tasks/ and test:

  • Create a task
  • Click to view details
  • Edit a task
  • Delete a task   

You should see the following page:

Dockerizing Our Django App

Create a Dockerfile 

In the root of the project, create a Dockerfile and add the following to it

Read the comments for more information about each line

Build & Run Locally in Docker

Build your image by running the following command in the root of the project:

docker build -t task-manager:latest .

Run database migrations inside a one-off container

Run the following command in the root of the project to run database migrations inside a one-off container:

Start your Django container, binding port 8000

Run the following command in the project root to start your container:

Visit http://localhost:8000/tasks/ and verify that your Task Manager is up and has the same behaviour as before.

Stop and remove the container when you’re done

Run the following command to stop and remove the container:

docker stop task-manager-dev docker rm task-manager-dev

Push the Docker Image to Amazon ECR

Before Elastic Beanstalk can pull your container, you need to store it in ECR (Elastic Container Registry).

Create an ECR repository

To store our image in ECR, we need to create a repository first. Run the following command to create a repository:

Take note of the repository URI in the output (e.g. 123456789012.dkr.ecr.us-east-1.amazonaws.com/task-manager) We need this for Elastic Beanstalk configuration.

Authenticate your Docker client

Run the following command to authenticate your Docker client:

Replace 123456789012 with the actual URI

Tag and push the image

Run the following command to tag your local image:

Run the following command to push the image to ECR:

docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/task-manager:latest

Your Docker image is successfully pushed to ECR.

Head to the AWS Console, In the search bar look for ECR and click on it. You should see the following page:

Deploy with Elastic Beanstalk  

Now that your Docker image is in ECR, let’s wire up Elastic Beanstalk to pull the image and deploy our Django application.

First, we need to create a new SSH key pair (you can use an existing one if you prefer)

This will create a new key file called task-manager-key.pem. Run chmod 400 task-manager-key.pem to set the proper permissions, and move the pem file to ~/.ssheb CLI looks in the ~/.ssh directory for the key file.

We need this key to connect to our instance and run the Django migration command.

Initialize EB project

In the root of the Django project, run the following command:

Create an environment and deploy

Run the following command to create an environment and deploy:

eb create task-manager-env  --keyname task-manager-key

This command creates and deploys our application in the Elastic Beanstalk and setup task-manager-key as our SSH key.

After running the command, you see something like the following in your terminal:

This can take a couple of minutes, wait until it's done.

When it's successfully completed, open the application in your browser by running eb open you can navigate to /tasks/ and /admin. The application is not fully functional yet since we didn't run the migrations

You can also go to the AWS Console, search for Elastic Beanstalk and click on the task-manager-prod environment. You can find the application URL in the Domain section.

Run database migrations

Let's ssh into the our environment and run Django migration. In the root of the project run eb ssh this should read the ssh key from ~/.ssh/task-manager-key.pem and connect to the environment. You should see something like the following in your terminal:

Now now run sudo docker ps to find the docker container id under the CONTAINER ID column.

Next run the docker exec -it bash to get a shell inside the container.

Now run python manage.py migrate to run the migrations. After finishing the migration, run exit to get out of the container.

Now run eb open to open the application and try CRUD operations to create, update and delete tasks.

Extra command

Here are some extra commands you can use:

Updating your App

When you push a new Docker Image, You should run the following command to deploy your application

eb deploy

Conclusion

In this article, we walked through the steps on how to deploy a Django app to AWS with Docker. We saw how simple it is to deploy to ElasticBeansTalk without a complex DevOps process or orchestration tools. Our deployment is scalable and fully managed, and we can keep our focus and time on building our application instead of wasting time on the DevOps tasks.

You can find the project code here

Here are the next steps to push this to the next level

  • Instead of using SQLite as our database, let's use AWS RDS as our database solution
  • Integrate your application with Appsignal for monitoring
  • Set up the actual domain name and SSL certificate for your application
  • Add CI/CD pipeline to automate deployments
  • Secure your environment variables

Related Blogs

Looking to learn more about Docker, Django and Deploy Django to AWS with Docker? These related blog articles explore complementary topics, techniques, and strategies that can help you master How to Deploy Django to AWS with Docker: Step-by-Step Guide for Scalable Apps.