Deploy a Production Django App With Elastic Beanstalk (Part 1)
By: Zack Petersen
Tags: Programming, Django, Elastic Beanstalk, AWS, Python

Preparing Beanstalk

Before you can use Beanstalk, you’ll need an AWS account. If you don’t have an account already, create one here.

Downloading the EB CLI

Let’s go back to the terminal window and install the Beanstalk CLI ( pipenv install --dev if you cloned the repo). Be sure to run the pipenv shell first:

pipenv install awsebcli --dev

I’m installing to dev here because we most likely won’t need the CLI on the production server, so it’s best to leave it for development only.

Confirm you have it installed with eb --version .

❯ eb --version

EB CLI 3.19.2 (Python 3.7.9)

Initializing elastic Beanstalk

Since we’re all set up with AWS and Beanstalk CLI, let’s get started!

eb init

This will prompt you to get set up with Beanstalk and configure the default application options.

Default Region : The default AWS region for beanstalk

: The default AWS region for beanstalk Credentials : Your AWS IAM user creds. Follow this guide to create one if you don’t have them already

: Your AWS IAM user creds. Follow this guide to create one if you don’t have them already App name : What your application will be named

: What your application will be named Python version : At the time of this writing, you can choose from Python 3.6 and Python 3.7. They are fundamentally different and this tutorial covers 3.7 with Gunicorn.

: At the time of this writing, you can choose from Python 3.6 and Python 3.7. They are fundamentally different and this tutorial covers 3.7 with Gunicorn. CodeCommit : Out of the scope of this tutorial — select no.

: Out of the scope of this tutorial — select no. SSH : Select create_new_keypair . Follow the prompts to create it and remember the name (default is aws-eb ). In my opinion, tailing the server logs is the easiest way to figure out deployment problems.

: Select . Follow the prompts to create it and remember the name (default is ). In my opinion, tailing the server logs is the easiest way to figure out deployment problems. Keypair: You’ll probably want to generate a new keypair, this will be passed as part of your SSH command to log in to the server.

Once you’re done setting this up, you’ll notice a new hidden directory in your project called .elasticbeanstalk .

There is a config.yml file in there and it’s everything you set up saved to your local directory for future use.

Pro tip: If you need to start over with Beanstalk on this project for whatever reason, delete this directory and run eb init again to change any defaults.

Creating the Beanstalk environment

Now that we have an application created on Beanstalk, let’s create our environment:

eb create

Again, you’ll be prompted with questions about what you would like to create.

Env Name : What your environment will be named.

: What your environment will be named. DNS CNAME prefix : Leave as the default.

: Leave as the default. Load Balancer Type : Choose Application.

: Choose Application. Spot Fleet Requests: Out of scope, select no.

After you finish with the setup, it will begin to create the environment for you and try to deploy it to Beanstalk. This takes a few minutes, but feel free to watch events and see what’s happening under the hood.

Adding .ebextensions

Once the deployment is finished, it should say it was successful. However, if you run eb open , you’ll get a 502 error when the webpage opens. This can difficult to debug because without a decent amount of digging, there’s no way to see why. Hint: it’s your WSGI path.

To fix this, we’ll create a new directory called .ebextensions . Inside, we create a file called django.config . Make sure you’re in at the project root for these commands.

Note: If you cloned the repo, this file already exists and you just need to uncomment the config settings.

mkdir .ebextensions

touch .ebextensions/django.config

Here’s how our project should look after creating the directory and file:

├── Pipfile

├── Pipfile.lock

├── db.sqlite3

├── .ebextensions

│ ├── django.config

├── images

│ ├── __init__.py

│ ├── admin.py

│ ├── api

│ ├── apps.py

│ ├── management

│ ├── migrations

│ ├── models.py

│ ├── tests.py

│ └── views.py

├── iotd

│ ├── __init__.py

│ ├── asgi.py

│ ├── settings.py

│ ├── urls.py

│ └── wsgi.py

├── manage.py

├── media

└── static

├── admin

└── rest_framework

Inside the django.config file, add the following:

option_settings:

aws:elasticbeanstalk:application:environment:

DJANGO_SETTINGS_MODULE: "iotd.settings"

PYTHONPATH: "/var/app/current:$PYTHONPATH"

aws:elasticbeanstalk:container:python:

WSGIPath: "iotd.wsgi:application"

aws:elasticbeanstalk:environment:process:default:

HealthCheckPath: "/api"

MatcherHTTPCode: "200-499"



container_commands:

01_makemigrations:

command: "source /var/app/venv/*/bin/activate && python3 manage.py makemigrations --noinput"

leader_only: true

02_migrate:

command: "source /var/app/venv/*/bin/activate && python3 manage.py migrate --noinput"

leader_only: true

03_createsu:

command: "source /var/app/venv/*/bin/activate && python3 manage.py createsu"

04_collectstatic:

command: "source /var/app/venv/*/bin/activate && python3 manage.py collectstatic --noinput"

leader_only: true

There’s a lot going on here, but this config file has all the commands to get set up on the server and have your Django app running properly, including setting up your WSGI path.

My first time deploying to Elastic Beanstalk with Amazon Linux 2 was challenging because of these config settings. At the time of writing, it’s not documented that you need to run the migration commands after manually activating the virtual environment (see docs here). They tell you to run django-admin.py migrate , which was throwing all sorts of errors for me and it was difficult to figure out what was wrong.

After some trial and error, I discovered the virtual environment on the application server is located at /var/app/venv/ . So in the config commands, I first source (activate) the virtualenv and then run my migration commands as normal.

### To run a command during deployment

source /var/app/venv/*/bin/activate && python manage.py migrate