Skinflint’s Guide to Serverless Django

Photo of Jarosław Wygoda

Jarosław Wygoda

Apr 2, 2019 • 9 min read
Netguru-Biuro-2018-4775-1

Zappa is a tool for deploying Python applications to AWS Lambda with API Gateway.

This way you can create an app using your favourite web framework and not to worry about maintaining and scaling your server. Unfortunately Zappa doesn't setup AWS resources such as database and static files bucket so we'll have to do it manually with Cloudformation templates.

In this tutorial we’ll create AWS S3 bucket for static files and PostgreSQL database on AWS RDS. Then we'll setup a Django project to connect to AWS resources and deploy it to our serverless hosting.

You can also check out this awesome Guide to using Django with Zappa and Free Templates for AWS CloudFormation.

AWS setup

In this section we’ll create IAM user to manage access to AWS services and resources securely. Then we’ll set up static files and and data storages.

IAM user

Create IAM user on AWS.

1. Select Programmatic access and click on Next to proceed with the next step of the wizard.

2. Click on Attach existing policies directly then Create policy. New tab will be opened.

3. Click on JSON tab and use example zappa policy. Remember to change to your Account ID from here and <s3_bucket from zappa_settings.json> to ‘zappainator-code’ (we’ll create it on Zappa initialization). Click on Review policy.

4. Name it as ‘zappainator-deploy’ and click on Create policy.

5. Return to the Add user tab and refresh available policies. Filter policies for ‘zappainator-code’ and select it. Click on Next: Review

6. Click on Create user.

7. Remember to save ‘Access key ID’ and ‘Secret access key’ for later authentication. Click on Close.

Static files

Create S3 bucket with public read access for hosting static files. Name it ‘zappainator-static’. We’ll use it in Django settings section.

Database

Create VPC, Security group and RDS for PostgreSQL Multiple Availability Zones are not covered in Free Tier. When configuring database parameters for the stack remember to change DBMultiAZ to false. You can read more about networking on AWS here. In case you need internet access from your Lambda you need one NAT Gateway or Instance in each SubnetZone in VPC (e.g. A and B in vpc-2azs.yaml). NAT Instances are less expensive and you can create one of them on EC2 t2.micro covered in Free Tier.

Django setup

When we’re done with AWS resources, we can configure our Django app to use it. We’ll install dependencies, start Django project and setup settings. After completing this section, we’ll have a fully functional Django app.

Install requirements

We’ll be working on Python 3.6. Zappa requires installing dependencies in a virtual environment.

Django
Django-storages
Zappa
Zappa-django-utils
Psycopg2-binary

Start project

Inside your working directory create some basic Django project. We’ll call it ‘zappainator’. (zappainator) $ django-admin startproject zappainator .

Edit zappainator/settings.py

Allowed hosts

In order to make this project work on AWS domain, we’ll and change ALLOWED_HOSTS to: ALLOWED_HOSTS = ['*'] Never do this on production! You’ll be vulnerable to HTTP Host header attacks.

Static files

Configure static files hosting on S3. Add ‘storages’ to the installed apps. We’ll also use some Environment Variables Available to Lambda Functions and S3 bucket (AWS_STORAGE_BUCKET_NAME) created in AWS static setup section.

INSTALLED_APPS = [
...
'storages',
]

AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_STORAGE_BUCKET_NAME = 'zappainator-static'
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/'

Database

Connect to PostgreSQL RDS created in AWS database setup section. You can get database credentials in database instance page.

INSTALLED_APPS = [
...
'zappa_django_utils',
]

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'zappadbname',
'USER': 'master',
'PASSWORD': 'this_is_not_a_good_password',
'HOST': 'zappa-db.abcd12345.us-east-1.rds.amazonaws.com',
'PORT': '5432',
}
}

Zappa setup

Now we have AWS resources setup and configured Django app we can deploy it to Lambda. In order to do so we’ll export environmental variables with AWS credentials and call Zappa deploy command. Zappa-django-utils will prepare database and static files. At the end of this section we’ll have a Django admin panel hosted on AWS Lambda.

Export environmental variables

You can export environmental variables on your project directory using direnv. Required variables:

* AWS_ACCESS_KEY_ID (created here)

* AWS_SECRET_ACCESS_KEY (created here)

* AWS_DEFAULT_REGION ( find your region)

* AWS_STORAGE_BUCKET_NAME (you’ll choose this name on zappa initialization)

Initialization

(zappainator) $ zappa init

On Zappa initialization you’ll be asked couple questions:

1. What do you want to call this environment? * Accept default ‘dev’

2. What do you want to call your bucket? * Call it ‘zappainator-code’

3. Where are your project’s settings? * Hopefully zappa will recognize our Django app and find settings module. It should be ‘zappainator.settings’.

4. Would you like to deploy this application globally? * Type ‘n’

5. Does this look okay? * If zappa_settings.json looks ok, accept it

Database

After creating VPC, Security group and Postgres RDS in AWS database setup section we can add it to VPC configuration in Zappa settings file so that it can connect to the database.

Here you can check out Group ID of client security group. Private Subnet IDs (your db subnets) can be found here or on your database instance page (subnets section).

{
"dev": {
...
"vpc_config" : {
"SubnetIds": [ "subnet-f3446aba", "subnet-c5b8c79e" ]
"SecurityGroupIds": [ "sg-9a9a1dfc" ]
}
}
}

Deployment

(zappainator) $ zappa deploy dev
(zappainator) $ zappa manage dev "collectstatic --noinput"
(zappainator) $ zappa manage dev create_pg_db
(zappainator) $ zappa manage dev migrate
(zappainator) $ zappa manage dev create_admin_user admin admin@example.com admin

You can check out if everything is ok by going to url returned by Zappa deploy command and logging into admin.

Summary

In this guide we managed to create a serverless Django app with access to RDS and S3 bucket. AWS resources were created using cloudformation. Application was deployed to AWS Lambda and API Gateway using Zappa.

Photo of Jarosław Wygoda

More posts by this author

Jarosław Wygoda

We're Netguru!

At Netguru we specialize in designing, building, shipping and scaling beautiful, usable products with blazing-fast efficiency
Let's talk business!

Trusted by:

  • Vector-5
  • Babbel logo
  • Merc logo
  • Ikea logo
  • Volkswagen logo
  • UBS_Home