Skriptmonkey
Posted on January 2, 2021
Wagtail is an actively developed, open source CMS built on Python and the Django web framework. In this tutorial, we will go over how to deploy Wagtail on a CentOS 8 server with MariaDB, Nginx, and Gunicorn.
Getting Started
Start with a fresh install of CentOS 8 and make sure your server is up to date.
dnf update -y
# reboot the server to apply the updates if needed.
Create a non-root sudo user, if you haven't already
useradd <username>
passwd <username> #enter new password
# add the user to the wheel group for sudo access.
usermod -aG wheel <username>
Next, lets install Python 3.8 using our newly created sudo user account.
su <username>
sudo dnf module -y install python38
Now we need to install both Nginx and MariaDB.
sudo dnf install nginx mariadb-server git
Setup the environment
At this point I like to create a Wagtail user account for managing the project code.
sudo groupadd --system wagtail
sudo useradd --system --gid wagtail --shell /bin/bash --home /opt/wagtail wagtail
sudo mkdir /opt/wagtail
sudo chown wagtail:wagtail /opt/wagtail
If you're hosting your project on GitHub or GitLab you can create an SSH key using the following commands.
sudo su wagtail
ssh-keygen -t rsa -b 2048 -C "<your email address>"
Generating public/private rsa key pair.
Enter file in which to save the key (/opt/wagtail/.ssh/id_rsa): <enter>
Created directory '/opt/wagtail/.ssh'.
Enter passphrase (empty for no passphrase): <enter password and/or press enter>
Enter same passphrase again: <enter password and/or press enter>
Your identification has been saved in /opt/wagtail/.ssh/id_rsa.
Your public key has been saved in /opt/wagtail/.ssh/id_rsa.pub.
You can get the key by running the following command.
cat /opt/wagtail/.ssh/id_rsa.pub
Setting up the database
Before we do anything else, lets start the MariaDB server and enable MariaDB on boot. Run these commands as root.
systemctl start mariadb
systemctl enable mariadb
Now, to give ourselves a nice, secure default setup run the following command.
mysql_secure_installation
Enter current password for root (enter for none): <enter>
Set root password? [Y/n] n
Remove anonymous users? [Y/n] <enter>
Disallow root login remotely? [Y/n] <enter>
Remove test database and access to it? [Y/n] <enter>
Remove test database and access to it? [Y/n] <enter>
Log in to MariaDB and create the database and user.
mysql -u root -p
Enter password: <enter>
CREATE DATABASE wagtail CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'wagtaildb'@'localhost' IDENTIFIED BY '<db user password';
GRANT ALL PRIVILEGES ON wagtail.* to wagtaildb@localhost;
FLUSH PRIVILEGES;
exit
Deploying your Project
The next step is to pull the code down from your repository. This guide assumes GitHub or GitLab is being used but feel free to use whatever you prefer. For this example I am using an empty project hosted on GitLab named Hello.
If you're following this guide closely you should be logged in as root right now.
Create the Python virtual environment in the wagtail users home directory.
su - wagtail
python3.8 -m venv .venv
source .venv/bin/activate
Upgrade setuptools and pip
pip install --upgrade setuptools pip
Create a directory to store the logs.
mkdir logs
Clone your git repositiory and cd into the project directory.
git clone https://gitlab.com/Skriptmonkey/hello.git
cd hello
Install the dependancies.
pip install -r requirements.txt
Migrate your database.
python manage.py migrate
And finally, collect your static assets. Your STATIC_ROOT variable in the base.py settings file should be set to someplace that Nginx can easily access. I go with '/var/www/static'. Run the following commands as root.
cd /opt/wagtail
source .venv/bin/activate
cd hello
python manage.py collectstatic --noinput
Change back to the wagtail user and create a new settings file in the settings folder called local.py
.
su - wagtail
vim /opt/wagtail/hello/hello/settings/local.py
In this settings file we want to import from .base
, add a SECRET_KEY
, and add in our ALLOWED_HOSTS
. How you generate a secret key is up to you. I like to create a "test" project on my local machine and take the SECRET_KEY
from that.
from .base import *
SECRET_KEY = '<your secret key>'
# SECURITY WARNING: define the correct hosts in production!
ALLOWED_HOSTS = ['exampleurl.com', 'www.exampleurl.com']
Configuring Gunicorn
If Gunicorn hasn't been added to the requirements.txt file in your project it should be. But if it isn't you can install it through pip as the wagtail user.
pip install gunicorn
We need to create a start file for gunicorn. This file will be called whenever you need to start the application server. Feel free to use your favorite text editor.
vim /opt/wagtail/gunicorn_start
Paste this into your new file and update the variables to reflect your project. Pay special attention to the DJANGO_SETTINGS_MODULE, Wagtail uses a different convention than Django by default.
#!/bin/bash
NAME="hello"
DJANGODIR=/opt/wagtail/hello
USER=wagtail
GROUP=wagtail
WORKERS=3
BIND=unix:/opt/wagtail/run/gunicorn.sock
DJANGO_SETTINGS_MODULE=hello.settings.production
DJANGO_WSGI_MODULE=hello.wsgi
LOGLEVEL=error
cd $DJANGODIR
source /opt/wagtail/.venv/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
exec /opt/wagtail/.venv/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
--name $NAME \
--workers $WORKERS \
--user=$USER \
--group=$GROUP \
--bind=$BIND \
--log-level=$LOGLEVEL \
--log-file=-
Make the file executable.
chmod +x ~/gunicorn_start
Make the run directory to store the unix socket file.
mkdir ~/run
Set the permissions on the new directory.
chmod 755 ~/run
Now exit out of the wagtail user so we can setup the systemd gunicorn service.
First create the systemd service file using your favorite editor.
sudo vim /etc/systemd/system/gunicorn.service
Add the following to the file:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=wagtail
Group=wagtail
WorkingDirectory=/opt/wagtail
ExecStart=/opt/wagtail/gunicorn_start
[Install]
WantedBy=multi-user.target
Start the gunicorn service and enable the service to start on boot.
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
Configuring Nginx
Lets get SELinux squared away before we start on configuring Nginx. We need to install the SELinux utilities.
sudo dnf install policycoreutils-python-utils -y
Now we add httpd_t
to the permissive domains in SELinux.
sudo semanage permissive -a httpd_t
While we're allowing things to happen on our server lets also allow both http and https through the server firewall.
sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --permanent --add-service=https
Change into the Nginx conf.d directory.
cd /etc/nginx/conf.d/
Once again, using your favorite editor create a config file for Nginx.
sudo vim wagtail.conf
Add this into the file:
upstream app_server {
server unix:/opt/wagtail/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
#listen [::]:80; # <- Uncomment this if you also have AAAA DNS record for IPV6.
server_name IP_ADDRESS_OR_DOMAIN_NAME; # <- insert here the ip address/domain name
keepalive_timeout 5;
client_max_body_size 4G;
access_log /opt/wagtail/logs/nginx-access.log;
error_log /opt/wagtail/logs/nginx-error.log;
location /static/ {
autoindex on;
alias /opt/wagtail/hello/static/;
}
location /media/ {
alias /opt/wagtail/hello/media/;
}
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
}
Test your Nginx configuration.
sudo nginx -t
Start the service and enable it on boot.
sudo systemctl start nginx
sudo systemctl enable nginx
Reboot the server.
sudo reboot
That's it!
You should now have a functional Wagtail site deployed.
Next I'd recommend configuring your webserver with an SSL certificate. Let's Encrypt is a good, free option.
Posted on January 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.