Wagtail is a powerful and highly extensible open-source CMS based on Django web framework.

In this tutorial you will read how to prepare your project for production deployment and how to get your site deployed on AWS EC2 and Digital Ocean.

If you are looking for other deployment tutorials checkout out one of these:

In this post:

In order to create a blog project let's run these commands in terminal.

They will create a directory, python virtual environment and spin up a wagtail project from the template in the current directory.

mkdir myblog
cd myblog
python3 -m venv env
source env/bin/activate
pip install wagtail
wagtail start myblog .

Before we continue with installing dependencies open the requirements.txt in your code editor and add 2 new lines: whitenoise and django-environ.

Your requirements.txt would look like this:

Django>=4.2,<5.1
wagtail>=6.1,<6.2
whitenoise==6.6.0
django-environ==0.11.2
psycopg2-binary==2.9.9
gunicorn==22.0.0

Then run this to install all dependencies:

pip install -r requirements.txt

Now open the file myblog/settings/base.py

Find the MIDDLEWARE and let's add whitenoise middleware right after SecurityMiddlware.

MIDDLEWARE = [  
    "django.contrib.sessions.middleware.SessionMiddleware",  
    "django.middleware.common.CommonMiddleware",  
    "django.middleware.csrf.CsrfViewMiddleware",  
    "django.contrib.auth.middleware.AuthenticationMiddleware",  
    "django.contrib.messages.middleware.MessageMiddleware",  
    "django.middleware.clickjacking.XFrameOptionsMiddleware",  
    "django.middleware.security.SecurityMiddleware",  
    "whitenoise.middleware.WhiteNoiseMiddleware", # new
    "wagtail.contrib.redirects.middleware.RedirectMiddleware",  
]

Also add WHITENOISE_USE_FINDERS=True line to the same file, you can add it to the end of the file.

Now open the myblog/settings/production.py and add these lines to make sure our project respects environment variables when deployed in production.

We need to make sure that ALLOWED_HOSTS, SECRET_KEY and DATABASES are set correctly according to environment variables, because you never should hardcode any of those values and place them in version control.

Your myblog/settings/production.py should now look like this:

import environ
import os
from .base import *

DEBUG = False

try:
    from .local import *
except ImportError:
    pass


env = environ.Env(
    # set casting, default value
    DEBUG=(bool, False)
)

SECRET_KEY = env('SECRET_KEY')

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['*'])

DATABASES = {
    'default': env.db(),
}
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

MEDIA_ROOT = env('MEDIA_ROOT', default=os.path.join(BASE_DIR, 'media'))  
MEDIA_URL = env('MEDIA_URL', default='/media/')

In the home/ directory create a directory management and an empty file __init__.py. In management directory create a directory commands and an empty file __init__.py in it. Empty __init__.py make these directories a python package and allows importing from them.

In commands directory create a file makesuperuser.py with the following content:

from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
from django.utils.crypto import get_random_string

User = get_user_model()


class Command(BaseCommand):
    def handle(self, *args, **kwargs):
        email = 'admin@example.com'
        new_password = get_random_string(10)
        try:
            u = None

            if not User.objects.filter(is_superuser=True).exists():
                self.stdout.write("No superusers found, creating one")
                u = User.objects.create_superuser(username='admin', email=email, password=new_password)
                self.stdout.write("=======================")
                self.stdout.write("A superuser admin has been created")
                self.stdout.write(f"Email: {email}")
                self.stdout.write(f"Password: {new_password}")

                self.stdout.write("=======================")
            else:
                self.stdout.write("A superuser exists in the database. Skipping.")
        except Exception as e:
            self.stderr.write(f"There was an error {e}")

This is a Django management command. It will check if a superuser already exists in a database. If it is not present, then it will create one with a generated password and print the password in logs. This automates the process of creation of the initial superuser, and doesn't require SSHing into a server to run the built-in createsuperuser command.

In the root of the project create a file release.sh:

#!/bin/bash

set -e
python manage.py migrate
python manage.py makesuperuser

This file will be used to apply migrations and check for super user existence and will be executed on each deployment(release phase).

Also create .gitignore file, which is useful to avoid cluttering our git repository with files that shouldn't be committed to version control.

env/
.idea/
__pycache__/
*.py[cod]
*$py.class
.vscode/
.DS_Store  
.AppleDouble  
.LSOverride

Now initialize the repository, add and commit the code.

git init
git add .
git commit -m'Initial commit'

Create a GitHub or GitLab repository, add the remote and let's deploy it with Appliku.

Deploy Wagtail on AWS EC2

In order to deploy Wagtail project on AWS EC2 you need to generate AWS keys first. Follow instructions in this guide

After you have keys setup open Appliku dashboard and go to the "Servers" tab.

Select AWS provider.

image

Select the region, instance type and the disk size. To fit in AWS Free Tier make sure the disk size to be <30GB.

image

image

Click "Create EC2 Instance".

You will be taken to the server page where you will see the setup process. When it is finished, go to Applications tab and create a new app from GitHub (or GitLab if you hosted your repository there).

Deploy Wagtail on Digital Ocean

If you choose to go with Digital Ocean first make sure to create a DO account.

You will need to generate a token here https://cloud.digitalocean.com/account/api/tokens/new

Make sure to select scopes both "Read" and "Write". We recommend to setup expiration to "Never" or "1 Year" to avoid service interruptions.

image

In Appliku dashboard go to Servers tab and click "Setup Credentials" for Digital Ocean. Paste and save the token and go back to Servers tab. You will be able to select Digital Ocean provider now.

image

Select the region and Droplet Type. For Droplet Size we strongly recommend to pick at least 1GB RAM instance so your server can build and run your app and the database.

Click "Create Droplet". image

Appliku will call Digital Ocean API and create a server for you and begin setup.

When that is finished you will be able to create the app and the database.

Deploy Wagtail with Appliku

Click on the "Applications" menu link.

image

If you haven't setup connection to will need to do that by clicking Setup Credentials.

When you are done you will be able to select the service you prefer. For this tutorial we'll go with GitHub

image

Give your app a name, select repository, branch and the server you have just created and click "Create Application".

image

Click on "Manage" in the databases block and add a database "Postgres 15" on the server we have just created.

image

image

image

Wait for it to get to "Deployed" status.

Go back to the application overview and click "Settings"

image

image

Go to the "Environment variables" tab. You see that our database's connection string is already there. Click "+ Add" and add variables: - "ALLOWED_HOSTS" must consist of the app name and ".applikuapp.com" so in our example it will be "wagtaildemo.applikuapp.com" - SECRET_KEY: any random long string. Must be kept secret - DJANGO_SETTINGS_MODULE must be set to myblog.settings.production

Now click "Save And Deploy" image

On the Processes tab go create two processes: web and release. The command for the web process: gunicorn myblog.wsgi --log-file -(watch out for the trailing dash -, it is important) The command for the release process: bash release.sh

image

On the volumes tab, create a volume for media files:

  • Container path: /volumes/media (path on which files will be accessible for your app)
  • URL: /media/
  • Environment Variable: MEDIA

image

Back on the "Build Settings" tab make sure that "Update Nginx Configuration on deploy" is checked and save changes. image

You can go back to the application overview page and see that deployment has started.

image

The first deployment might take a bit longer, because the dependencies take some time to install at first run. Next deployments will take less time if you haven't changed requirements.txt file.

Click on "View Application"

image

image

Congratulations! You have deployed your Wagtail app!