Installing Mautic with PHP7-FPM on Docker, Nginx, and MariaDB on Ubuntu 16.04

View recent blog entries

Mautic is an open source marketing automation web application. Here at the OER Foundation, we use it to manage enquiries from prospective learners and partner institutions, to deliver timely emails to cohorts of learners undertaking our partner's online courses, and to measure our effectiveness in achieving our goals and mission: to makes higher education accessible to everyone.

Like proprietary tools (Campaign Monitor, Constant Contact, MailChimp, and others) Mautic provides Javascript forms that can easily be incorporated into your organisational website (see the forms at the bottom of each page of our website for example) by copying and pasting the "embed" code... These can be customised to your heart's content, and they allow you to engage with site visitors and make it easy for them to opt into receiving further communication from you. Based on how they interact with you subsequently, you can tune your communication with them to make it more relevant and compelling.

Communications can be newsletters, lead follow up emails, and, in our case, a variety of course-specific email communications posts which convey specific instructions to cohorts of learners. Mautic has a full HTML email templating system with a variety of sharp looking pre-made templates, among other advanced capabilities. I like to describe Mautic to people as "MailChimp, on steroids".

You can either purchase a supported Mautic service for your organisation, which we did for a while (they have just recently increased the prices substantially) but because it's open source, if you're interested, you can also install your own instance and track the development of the Mautic software. We have made a Docker Image you can download and the recipe for how to use it, and or modify it to better suit your purposes is on Github.

Our configuration

We run Mautic in the following configuration. On our virtual host, we run Ubuntu Linux 16.04 with Nginx as the web server and MariaDB (a more open drop-in replacement for MySQL) as the database. We use ufw as the firewall, and Let's Encrypt for (automatically) procuring signed SSL certs.

We use AWS's Simple Email Service for sending outgoing email (running your own email servers is hard - not something to be entered into lightly), and we run Docker containers and the additional Docker Compose scripts.

Preparing the host

First things first, make sure you're logged into your host (probably via SSH) as a user who has "sudo" capabilities! You need to log into the host from your local machine. We recommend setting up key-based authentication.

Keeping it secure

No computer system is ever full secure - there're always exploits waiting to be found, so security is a process of maintaining vigilance. Part of that is reducing exposure - minimising your "attack surface". Use a firewall - "ufw" is installed on Ubuntu by default. Make sure you've got exceptions for SSH (without them, you could lock yourself out of your machine! Doh!).

Run the following commands to allow your Docker containers to talk to other services on your host.

sudo ufw allow in on docker0
sudo ufw allow from 172.17.0.0/24 to any
sudo ufw allow from 172.18.0.0/24 to any
sudo ufw allow from 172.19.0.0/24 to any
sudo ufw allow from 172.20.0.0/24 to any

Specifically for Docker's benefit, you need to tweak the default Forwarding rule (I use "vim" as my editor. If you don't know how to/want to use it, replace vim with nano everywhere you see it in the following - nano's easier to use for simple edits like this):

sudo vim /etc/defaults/ufw

and copy the line DEFAULT_FORWARD_POLICY="DROP" tweak it to look like this (commenting out the default, but leaving it there for future reference!):

#DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_FORWARD_POLICY="ACCEPT"

You also have to edit /etc/ufw/sysctl.conf and remove the "#" at the start of the following lines, so they look like this:

sudo vim /etc/ufw/sysctl.conf

# Uncomment this to allow this host to route packets between interfaces
net/ipv4/ip_forward=1
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

and finally restart the network stack and ufw on your server

sudo service networking restart
sudo service ufw restart

Install Nginx

We like the efficiency of Nginx and clarity of Nginx configurations over those of Apache and other open source web servers. Here's how you install it.

sudo apt-get install nginx-full

To allow nginx to be visible via ports 80 and 443, run

sudo ufw allow "Nginx Full"

Note: make sure your hosting service is not blocking these ports at some outer layer (depending on who's providing that hosting service you may have to set up port forwarding).

Install MariaDB

MariaDB is effectively a drop-in alternative to MySQL and we prefer it because it's not controlled by Oracle and has a more active developer community. On Ubuntu, MariaDB pretends to be MySQL for compatibility purposes, so don't be weirded out by the interchangeable names below. Install the server and the client like this.

sudo apt-get install mariadb-server-10.0 mariadb-client-10.0

You need to set a root (admin) user password - you might want to create a /root/.my.cnf file containing the following (replacing YOURPASSWORD) to let you access MariaDB without a password from the commandline:

[client]
user=root
password=YOURPASSWORD

You should now be able to type "mysql" at the command prompt

Tweak the configuration so that it's listening on

sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf

and copy the bind-address line and adjust so it looks like this - we want MariaDB to be listening on all interfaces, not just localhost (127.0.0.1)...

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#bind-address           = 127.0.0.1
bind-address            = 0.0.0.0

Then restart MariaDB:

sudo service mysql restart

It should now be listening on port 3306 on all interfaces, i.e. 0.0.0.0.

Now set up the database which will hold Mautic's data. Log into the MySQL client on the host (if you've created a .my.cnf file in your home directory as describe above, you won't need to enter your username and password):

mysql -u root -p

Enter your root password when prompted. It's also a good idea to gin up a password for your "mautic" database user. I usually use pwgen (sudo apt-get install pwgen) - for example running this command will give you a single 12 character password without special characters (just numbers and letters):

pwgen -s 12 1
T7KR2osrMkyC

At the prompt (which will look something like MariaDB [(none)]>) enter the following lines (putting your password in place of [passwd]):

CREATE DATABASE mautic CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER "mautic"@"%" IDENTIFIED BY "[passwd]";
GRANT ALL ON mautic.* to "mautic"@"%";
FLUSH PRIVILEGES;

Then enter \q to exit.

Docker and Docker Compose

Finally, to run the Mautic app itself the way we like to run it, you'll need Docker and Docker Compose installed. For Docker, follow these excellent instructions. And here're instructions for Docker Compose.

Follow these "post-installation steps" too - your unprivileged user should be set up to run Docker as well - it'll make your life easier.

Setting up Mautic

Once you've got them install, you can grab our git repository. To do that, you'll need to install git (sudo apt-get install git) and you'll install the Docker configurations, and create a place to hold the Mautic codebase on the host's filesystem. I do that in my user's home directory - so first we'll got there:

cd ~

Then install the git repository in a directory called "docker-mautic":

git clone git@github.com:oeru/docker-mautic.git

Then we need to go into that directory and create the Docker Compose configuration:

cd docker-mautic
cp docker-compose.yml-sample docker-compose.yml

Edit your docker-compose.yml and put in your details to replace the [placeholders].

vim docker-compose.yml

Your "hostname" will be the IP address assigned to your host by Docker. You can find it by running this:

ifconfig | grep -1 "docker0" | grep "inet addr"

It should be 172.nn.0.1 where nn is probably between 16-20.

You also need to create a directory for the source code of Mautic to go into. I create a a directory called mautic with a src directory in it:

mkdir -p mautic/src

When you first run up the Mautic Docker instance, it will download the current (at that time) Mautic release and copy it into the directory on your host that you've designated.

Configuring Outgoing Mail

Your Mautic configuration has to send out emails for two separate reasons:

  1. emails to your Mautic Contacts, and
  2. emails to you and/or your system administrators about your Mautic server.

The first one is crucial - it's necessary for Mautic to function properly. You do this through the Mautic interface after you've set things up. You might want to set up "bounce management", too so you can adjust your Contacts when, invariably, you have emails that are no longer valid...  You might want to employ an "SMTP-as-a-service" provider. We currently use Amazon's Simple Email Service (SES)... but there are dozens of others. For testing, you can just use any SMTP service you have available to you.

But you also need to be able to receive emails from Mautic so that it can alert you to any issues, like, for example, if your scheduled tasks ("cron jobs" that run on your Docker instance) fail to run properly, which can lead to lots of issues. For that, we use msmtp, an app which acts as minimal SMTP relay. You'll need to set up the msmtp configuration to set that up (assuming your mautic dir is ~/mautic):

cp conf/msmtp/msmtprc-sample mautic/msmtprc
vim mautic/msmtprc

And configure the values for the four [placeholders] provided.

Finally, you're ready to launch. First grab the latest Mautic Docker image we've created.

docker pull oeru/mautic

Then, fire up the container. If it's working, you should see a screen which tells you your Mautic Mysql/MariaDB details:

docker-compose up

You can stop it by hitting "CTRL-C" and following the directions. To start it so keeps running even after you log out:

docker-compose up -d

You can always check it's running with

docker ps

and you can log into your instance by copying the 12 character container ID and copying it into this command:

docker exec -it [containerID] bash

If all is well, you have a Docker container, running PHP 7 (in FPM mode) ready to serve Mautic via a web socket, which is visible (by default) on port 9000 of the host. Now all we need to do is configure your nginx webserver to talk to it.

Configuring the web server

Although the docker-compose.yml includes a commented out configuration for a Docker container running Nginx (and a default.conf configuration file that should copied to [your mautic directory]/nginx-default.conf linked from the container), that either requires making the container directly visible on the external interface of the host (precluding running any other websites on the server) or the additional complexity of a reverse proxy to make the nginx serving Mautic visible externally. That usually takes another nginx or apache (or some other webserver) instance on the host.

To simplify things, we've gone with having our nginx instance running on the host, and talking via sockets to the PHP service running on the Docker container. In the git directory you've downloaded, we've provided a documented nginx configuration file - nginx-on-docker-host.conf. To enable it (this is also documented in the file itself) copy it to, say /etc/nginx/sites-available/mautic - note that we initially have the SSL host commented out to allow you to set up the Let's Encrypt certificates below...

sudo cp nginx-on-docker-host.conf /etc/nginx/sites-available/mautic
sudo vim /etc/nginx/sites-available/mautic  # to tweak the configuration
sudo ln -sf /etc/nginx/sites-available/mautic /etc/nginx/sites-enabled

Check to see if there're any configuration errors

sudo nginx -t

If there're problems, fix them, and then make it live

sudo service nginx reload

and then edit it to tweak any settings required to, for example, configure your Mautic site's external domain name...

Configuring encryption

See our Let's Encrypt howto!

Conclusion

And you're done - you can go to your domain name via https://[yourdomain] and you should get the Mautic login page. You can log in with the username "admin" and the password "mautic". Change the password immediately, and create an admin user for yourself with a strong password.

You can update the Mautic app itself in place through the internal app update functionality (where Mautic knows how to upgrade its own code and will alert you there's an update available for your instance).

Updating the container should be as easy as either doing another

docker pull oeru/mautic

and then shutting down Docker container via a

docker-compose stop

removing the old containers (this won't remove any data you want to save if you followed the directions above! But remember to do it in the right directory!) via

docker-compose rm -v

and then restarting it via

docker-compose up -d

That should give you the latest version of the container...

Of course, always make sure your Ubuntu 16.04 host is up-to-date! Hope this helps a few people!