Using this tutorial you will be able to setup your Wagtail project to run a dynamic website, build a development environment and finally deploy on a production machine, all of this using Docker, so that everythning runs in a closed environment

In this tutorial series we are aiming at rapidly setup your website using Wagtail CMS and Docker, served by Nginx and using SSL with Let's Encrypt

Using this tutorial you will be able to setup your Wagtail project to run a dynamic website, build a development environment and finally deploy on a production machine, all of this using Docker, so that everythning runs in a closed separate environment so you don't pollute the rest of your machine and won't damage your website if you are using the machine for something else. The following tutorial was done in Debian.

This first part focuses on running a Wagtail CMS inside a Docker container.

Installing a virtual environment and preparing Wagtail

First, we need to set a virtual environment in order to install Wagtail.

Create the project folder:

mkdir my_project

Change directory to enter my_project:

cd my_project

Start your git in order to keep track of your project changes and push them to your remote machine (the one ). In case it is not installed:

sudo apt install git
git init

Create a .gitignore file so that git ignores unwanted files:

# Let's encrypt with certbot
certbot/ 

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
 
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache
 
# Scrapy stuff:
.scrapy
 
# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py
 
# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json
 
# Pyre type checker
.pyre/
 
# macOs
.DS_Store

# SQLite database files
*.sqlite3

# Syncthing
*.sync-conflict-*

You have to remember to commit your changes at each step you find important. First add the files to commit:

git add changed_or_new_file

Or to add any new or modufied files:

git add .

Then register the commit with:

git commit -m 'reason for your commit'

If Python and Python's package manager PiP are not installed already:

sudo apt-get install -y python3 python3-pip

Create the virtual environment for PiP and activate it. Install virtualenv first if not available already:

sudo apt install python3-virtualenv

Create the virtualenv

virtualenv -p python3 venv

This will create the files needed to install Python packages without polluting the rest of the system (so each project only gets the packages it requires)

Activate the envrionment with:

source venv/bin/activate

Now you can install Wagtail with python package installer PiP:

pip install wagtail

Wagtail will automatically create and install the project, much like Django, with:

wagtail start my_project

Change directory to my_project subfolder which was created by wagtail:

cd my_project

Packages required to run Wagtail are already set in requirements.txt, so you just have to run the following commend inside /path/to/my_project/my_project/ to make sure you have everything your project need when you installed Wagtail.

pip install -r requirements.txt

Populate the SQlite database with the first migration:

python manage.py migrate

Create a superuser to access admin page, you will be asked for a username, email and password:

python manage.py createsuperuser

Test that everything is in order and the projct can run:

python manage.py runserver

It should display a page at:

http://127.0.0.1:8000/

Deactivate Python's virtual environment running the following command:

deactivate

Running Wagtail inside a Docker container

Docker is used to make your system as close to a production envrionment as possible, like having a parallel system compartimentalised from the rest of the system. It is especially important when multiple apps are running to make your project viable, so that you don't interfere with them while doing other developments on the same machine.

### Installing Docker

The next few steps will allow you to add Docker to your list of packages on your machine so that you will be able to easily install and update it:

sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

 echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update 

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Create docker group if it does not exist:

sudo groupadd docker

Tie docker to your user:

sudo usermod -aG docker your_username

To get Docker to run, you have to log out of your current session or SSH session and log in again or restart your machine.

Check if it's under your group capabilities:

groups your_username

Run test docker with:

docker run hello-world

It will install the image as a test as such: Hello from Docker! This message shows that your installation appears to be working correctly. [...]

### Using Docker as a container for Wagtail

A Dockerfile should already exist inside your Wagtail project folder, created by Wagtail's installation process as such:

#Full path to environment Python, usually my_project/venv/bin/python
ENV PYTHONPATH "${PYTHONPATH}:/your/custom/path"

# Use an official Python runtime based on Debian 10 "buster" as a parent image.
FROM python:3.8.1-slim-buster

# Port used by this container to serve HTTP.
EXPOSE 8000

# Set environment variables.
# 1. Force Python stdout and stderr streams to be unbuffered.
# 2. Set PORT variable that is used by Gunicorn. This should match "EXPOSE"
#    command.
ENV PYTHONUNBUFFERED=1 \
    PORT=8000

# Install system packages required by Wagtail and Django.
RUN apt-get update --yes --quiet
RUN apt-get install --yes --quiet --no-install-recommends build-essential
RUN apt-get install --yes --quiet --no-install-recommends libpq-dev
RUN apt-get install --yes --quiet --no-install-recommends libmariadbclient-dev
RUN apt-get install --yes --quiet --no-install-recommends libjpeg62-turbo-dev
RUN apt-get install --yes --quiet --no-install-recommends zlib1g-dev
RUN apt-get install --yes --quiet --no-install-recommends libwebp-dev
RUN apt-get install --yes --quiet --no-install-recommends python3-opencv

RUN rm -rf /var/lib/apt/lists/*

# Install the application server.
RUN pip install "gunicorn==20.0.4"

# Install opencv-python
RUN pip install opencv-python

# Install the project requirements.
RUN pip install "Django==3.1"
RUN pip install "wagtail==2.11"
RUN pip install psycopg2
RUN pip install Faker

# Use /app folder as a directory where the source code is stored.
WORKDIR /app
COPY  . .

Adjust the following lines to the port you want your project to be served on:


EXPOSE 8000
PORT=8000

This next command, you will use often to build your project in Docker. Each time you make a change in my_project/my_project/, you must build your docker image. Building the Docker image takes some time so plan accordingly.

docker build . -t my_project/backend

You are ready to run your docker image using:

docker run -it -p 8000:8000 my_project/backend bash

Here you can change your port (8000) to suit your needs.

You will be greeted by a prompt from inside the image. Try and run your server:

python manage.py runserver 0.0.0.0:8000

Here the port should be the same as the one used to start the docker image. Using 0.0.0.0 as the ip address means that Wagtail will serve files on any ip address the machine is running on (local, external if the port permits it). Migrations issues should be displayed, but we'll ignore them to check if we can access the website.

Connect to your website and you should be met by the same migrations error. Let's correct our mistake and run migrations:

python manage.py makemigrations && python manage.py migrate

You can run the server again and your site should be up. To login, you will need to create a super user from within the Docker image. First stop the server with Ctrl+C. Then run the command to create a super user again, this time to access admin page inside the Docker container:

python manage.py create superuser

You can now login.

Conclusion

In this part we have been able to install the necessary setup to run a Wagtail website inside a Docker container.

In the next part, we wlll see how to tie Wagtail, Gunicorn and Nginx to run our website for production.

wagtail-docker-nginx


Required for comment verification