Mura Cloud (AWS)

The Mura AWS hosting configuration creates a secure, redundant, self-healing Virtual Private Cloud (VPC) via Amazon Web Services (AWS) and a host of Amazon- and integrated 3rd-party solutions. 

VPC lets you provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network. Web servers and application servers in the VPC can leverage Amazon EC2 elasticity and Auto Scaling features to grow and shrink as needed. Every Mura VPC is private and dedicated solely to the customer.

Route53 with Service Discovery is used to provide communication between the Mura Docker containers, which allows for multiple containers and multiple services. Along with its own Service Discovery, each VPS also has its own private Certificate Manager for managing SSL and other certifications; a Secrets Manager for separating API and other private keys/passwords from deployed repositories, and an Elastic File System for file storage.

Mura

Mura is provisioned via Docker containers. Docker “containerizes” all the services required to spin up an instance of Mura, including web server, database and application engine. Many of these services are themselves Docker Images, integrated into the instance via the “compose” file.

The Mura Docker container will hold the latest official Mura Image, with options to use the Lucee or Adobe CF2016 based upon the CommandBox Docker Image, or the official Lucee Docker Image. The Docker compose may optionally include references to other images such as a mail server, Elastic Search or other integrated services.
The Mura Docker “compose” file contains references to the above images, as well as the environment variables needed to complete the installation.

Mura & Docker

A chief advantage of Docker and containers in general is that they can be assembled from a variety of Images, and those Images configured in innumerable ways to suit the specific use case.


The official Mura Docker Image can be accessed via:

docker pull blueriver/docker-muracms

The Docker files contained within this image can be used to assemble your own custom Docker container. There are several “core” Images to consider when assembling your Mura Docker container:

blueriver/muracms:latest (Dockerfile)
       …  The "Official" Blue River Mura CMS Docker image.
:7.1-commandbox-lucee5 (Dockerfile) …   
       … Uses the :lucee5 CommandBox Docker image as the base image.
:7.1-commandbox-adobe2016 (Dockerfile)
       … Uses the :adobe2016 CommandBox Docker image as the base image.
:7.1-lucee5 (Dockerfile)
       … Uses the :lucee5 Lucee Docker image as the base image.

Other images you may want to consider are:

  • Database: MySQL, PostGres, Microsoft SQL
  • Mail: MailCatcher
  • Elastic Search

Primary thoughts to consider when implementing Docker and Mura CMS into your workflow include:

Which CFML engine do you want to use? Adoble ColdFusion? Or Lucee?

Do you want to use one of the convenient Commandbox images for your desired CFML engine, or create your own?

Which database engine do you wish to use? MySQL, Postgres, or Microsoft SQL Server?

Do you want to be able to modify Mura CMS core files, and only abstract the CFML engine? (Rare)

Do you want to abstract Mura CMS core files, and simply have them included in the image itself? (Common)

If abstracting Mura CMS core files, do you want to be able to modify modules, plugins, sites, and/or themes? (Common)

Once you have the answers to these questions, you will be able to better select the appropriate Docker image, and docker-compose files to use. 

Building Your First Image

If you're completely new to Docker, the Docker Documentation area is a tremendous resource. You will also find the Udemy course titled "Docker Mastery: The Complete Toolset From a Docker Captain" extremely helpful in getting you up to speed rather quickly.

To build your image, you may use one of the Dockerfile and/or docker-compose.yml files located under any of the following examples.
After downloading and placing the Mura Docker Github repository into a local directory (and assuming you have the latest version of Docker running on your system), enter the following terminal command-line execution within the repository directory (which will first build the image “as is” and then run aka “spin up” the container):

  • docker-compose build --no-cache
  • docker-compose up 

This assembles the docker image based upon the docker-compose.yml file within that directory, “spinning up” the Image so that you will now have a working local copy of Mura running.

Examples

Examples are located under https://github.com/blueriver/docker-muracms/tree/master/examples. Each example contains a docker-compose.yml file. Using your terminal, you may cd into the desired example directory, and then issue the   $ docker-compose up  command.

Unless you've modified any of the docker-compose.yml files, the information outlined below for each example should be correct. Feel free to inspect the docker-compose.yml files to confirm, and/or to modify as desired.

blueriver-muracms-mysql

This example uses the "Official" Mura CMS Docker image as the base image. It abstracts the Mura CMS core files, and includes host directories under the www directory for editing modules, plugins, sites, and themes. The MySQL database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/blueriver-muracms-mysql directory.

  • Website:
  • Image: "Official" Mura CMS Docker Image (blueriver/muracms:latest)
  • Domain: http://localhost:8001
  • Usr: admin
  • Pwd: 5trongP@55w0rd
  • Database:
  • Image: MySQL (mysql:5.7.19)
  • Domain: http://localhost:5001
  • Usr: root
  • Pwd: 5trongP@55w0rd
  • commandbox-adobe2016-mssql

This example uses the CommandBox Adobe2016 image as the base image. It abstracts the Mura CMS core files, and includes host directories under the www directory for editing modules, plugins, sites, and themes. The Microsoft SQL Server database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/commandbox-adobe2016-mssql directory.

To build a new image (to get the latest updates) and then run it, use:

  • docker-compose build --no-cache
  • docker-compose up 

Your site should be available, after the scripts have finished running.

  • Website:
  • Image: blueriver/docker-muracms:7.1-commandbox-adobe2016
  • Domain: http://localhost:8002
  • Usr: admin
  • Pwd: 5trongP@55w0rd
  • Database:
  • Image: Microsoft SQL Server (microsoft/mssql-server-linux:latest)
  • Domain: http://localhost:5002
  • Usr: sa
  • Pwd: 5trongP@55w0rd
  • commandbox-lucee5-mysql

This example uses the CommandBox Lucee5 image as the base image. It abstracts the Mura CMS core files and includes host directories under the www directory for editing modules, plugins, sites, and themes. The MySQL database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/commandbox-lucee5-mysql directory.

To build a new image (to get the latest updates) and then run it, use:

  • docker-compose build --no-cache
  • docker-compose up 

Your site should be available, after the scripts have finished running.
Website:
Image: blueriver/docker-muracms:7.1-commandbox-lucee5
Domain: http://localhost:8003
Usr: admin
Pwd: 5trongP@55w0rd
Database:
Image: MySQL (mysql:5.7.19)
Domain: http://localhost:5003
Usr: root
Pwd: 5trongP@55w0rd
commandbox-lucee5-postgres
This example also uses the CommandBox Lucee5 image as the base image. It abstracts the Mura CMS core files and includes host directories under the www directory for editing modules, plugins, sites, and themes. The Postgres database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/commandbox-lucee5-postgres directory.
To build a new image (to get the latest updates) and then run it, use:
docker-compose build --no-cache
docker-compose up 
Your site should be available, after the scripts have finished running.
Website:
Image: blueriver/docker-muracms:7.1-commandbox-lucee5
Domain: http://localhost:8004
Usr: admin
Pwd: 5trongP@55w0rd
Database:
Image: Postgres (postgres:9.6.5-alpine)
Domain: http://localhost:5004
Usr: muradb
Pwd: 5trongP@55w0rd
lucee5-mysql
This example uses the Lucee Lucee5 image as the base image. It abstracts the Mura CMS core files and includes host directories under the www directory for editing modules, plugins, sites, and themes. The MySQL database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/lucee5-mysql directory.
To build a new image (to get the latest updates) and then run it, use:
docker-compose build --no-cache
docker-compose up 
Your site should be available, after the scripts have finished running.
Website:
Image: blueriver/docker-muracms:7.1-lucee5
Domain: http://localhost:8005
Usr: admin
Pwd: 5trongP@55w0rd
Database:
Image: MySQL (mysql:5.7.19)
Domain: http://localhost:5005
Usr: root
Pwd: 5trongP@55w0rd
lucee5-mysql-nofiles
This example uses the Lucee Lucee5 image as the base image. It abstracts the Mura CMS core files and also abstracts the modules, plugins, sites, and themes directories. In other words, all changes are stored in the mounted volumes. The MySQL database image is added in the docker-compose.yml file. To run this example "as-is", you should be able to simply run  $ docker-compose up  from within the examples/lucee5-mysql-nofiles directory. To view the volumes created, you can always run $ docker image ls.
To build a new image (to get the latest updates) and then run it, use:
docker-compose build --no-cache
docker-compose up 
Your site should be available, after the scripts have finished running.
Website:
Image: blueriver/docker-muracms:7.1-lucee5
Domain: http://localhost:8005
Usr: admin
Pwd: 5trongP@55w0rd
Database:
Image: MySQL (mysql:5.7.19)
Domain: http://localhost:5005
Usr: root
Pwd: 5trongP@55w0rd

Docker Compose
The Docker “compose” file is the file that identifies the Images to run, as well as the configuration for the composition aka “spin up”. For further information,  refer to the docker compose document on the Docker documentation website.
Below is an example docker-compose.yml file like those located in the base directory for each of the examples listed above.
version: '3.3'


services:


  muracms:
    image: blueriver/muracms:latest
    depends_on:
      - svc_muradb
    environment:
      MURA_ADMIN_USERNAME: admin
      MURA_ADMIN_PASSWORD: 5trongP@55w0rd
      MURA_ADMINEMAIL: youremail@domain.com
      MURA_APPRELOADKEY: appreload
      MURA_DATASOURCE: dsn_muracms
      MURA_DATABASE: muradb
      MURA_DBTYPE: mysql
      MURA_DBUSERNAME: root
      MURA_DBPASSWORD: 5trongP@55w0rd 
      MURA_DBHOST: svc_muradb
      MURA_DBPORT: 3306
      MURA_SITEIDINURLS: "false"
      MURA_INDEXFILEINURLS: "true"
      MURA_TESTBOX: "true"
      MURA_USESSL: "false"
    volumes:
      - vol_muracms_modules:/var/www/modules
      - vol_muracms_plugins:/var/www/plugins
      - vol_muracms_sites:/var/www/sites
      - vol_muracms_themes:/var/www/themes
    ports:
      - "8888:8888"


  # DB
  svc_muradb:
    image: mysql:5.7.19
    environment:
      MYSQL_DATABASE: muradb
      MYSQL_ROOT_PASSWORD: 5trongP@55w0rd
    volumes:
      - vol_muradb:/var/lib/mysql
    ports:
      - "5555:3306"


# Mounts
volumes:
  vol_muradb:
  vol_muracms_modules:
  vol_muracms_plugins:
  vol_muracms_sites:
  vol_muracms_themes:
Mura Environment Variables
A key component to note is the use of Mura environment variables, which developers of pre-Docker Mura websites will likely recognize.
    environment:
      MURA_ADMIN_USERNAME: admin
      MURA_ADMIN_PASSWORD: 5trongP@55w0rd
      MURA_ADMINEMAIL: youremail@domain.com
      MURA_APPRELOADKEY: appreload
      MURA_DATASOURCE: dsn_muracms
      MURA_DATABASE: muradb
         …etc.
These variables are mapped to the values you would find in the config/settings.ini.cfm file within Mura. In this case, they are hard-coded into the file. For automated deployments (see Mura Pipeline, below), many of these values would be represented as string variables, to be replaced prior to the build process by the automation service.
Mura Pipeline
 Mura uses Buddy.Works as the automation pipeline for assembling, configuring and deploying the Mura Docker Container to AWS.

Pipeline automation accomplishes several key tasks:
Unit Testing
Injection of passwords and API keys which we do not want stored in code repositories
Standard build scripts
Custom build scripts for specialized deployments
Deployment to AWS
Notifications on success/failure
For Mura deployments, there are two pipelines: Review (staging), where the pipeline is triggered whenever the associated repository branch is updated, and Production (live) where the pipeline is triggered manually (for obvious reasons).


Pipeline Actions
 In the case of a standard Mura deployment, our Buddy.Works pipeline executes a series of actions to configure the associated repository. The repository is the project-specific codebase alone. A series of node deploy scripts are first run against the codebase.
Next, the Docker Images for Mura, Application Engine (ie. Lucee) and all others are assembled via the associated Dockerfile.mura (see Docker Image: Dockerfile.mura, below), followed by the NGINX Container build. These two containers are then deployed to the appropriate AWS Availability Zone, and a final deploy script is run to initialize the instance.
This process addresses all the tasks listed above, with automated exit should any issues from Unit Testing onward be detected.
Obvious Advantages
There are several obvious advantages to running your pipeline, beyond automation. First, it formalizes the process of deployment, removing the opportunity for human error. Second, it democratizes the process, so that the entire development team is able to see their changes integrated to the shared codebase (and, specifically, the staging server) within a formalized process. Finally, it allows for the fine-tuning and formalization of specialized use-cases, existing within the pipeline as optional or alternate build stages.
There are other non-obvious advantages as well, such as the logs and analytics generated.
Mura Build Process
There are several configuration files that are used in deployment to the staging and live environments of the VPC. You can view examples of these in a GitHub Gist.
Mura Configuration: cfapplication.cfc
This file configures the instance variables based upon the environment (default configurations found in the Mura /config/settings.ini.cfm file) and Docker compose environment variables. Separate configurations can be used for staging (review) and live (production), for instance.
this.ramBase = {
    class: 'lucee.runtime.cache.ram.RamCache'
    , storage: false
    , custom: {
        "timeToIdleSeconds":"3600",
        "timeToLiveSeconds":"10800"
    }
    , default: ''
};


//This must be done per site
this.cache.connections["default-data"] = duplicate(this.ramBase);
this.cache.connections["default-output"] = duplicate(this.ramBase);
NGINX Configuration: default.conf
NGINX can be used in a variety of ways, from load balancing to caching. One specific way we use it is for proxying our AWS S3:
  set $s3 "s3host";
  set $bucket "s3bucket";
  set $proxy "proxyhost";
Docker Image: Dockerfile.mura
As per the Mura Pipeline build process (above), these is the command-line instructions for assembling our Mura Docker image. In this file we run startup parameters for the cfml engine, integrate Fusion Reactor, and importantly run a health check on the image.
HEALTHCHECK --start-period=3m CMD curl --fail http://localhost:8888/?healthcheck || exit 1
NGINX Image: Dockerfile.nginx
This script runs during the assembly of the NGINX Docker Image. As with the NGINX default.conf (see above), this establishes the proxy settings for the deployment.
Docker Compose: docker-compose.yml
This is the “compose” file for the Mura Docker image created for our automated (Buddy.works) deployments.
environment:
    MURA_ENVIRONMENT: local
    LUCEE_JAVA_OPTS: "-Xms512m -Xmx1536m"
    MURA_DATASOURCE: ${dbname}
    MURA_DATABASE: ${dbname}
    MURA_DBTYPE: mysql
    MURA_DBUSERNAME: ${dbusername}
    MURA_DBPASSWORD: ${dbpassword}
You will notice the previously mentioned string variables spread throughout. These act as placeholders for private keys and password can be injected into these files (via Buddy.Works, Amazon Secrets Manager + ECS, etc.).
Mura in the VPC
Mura instances are spread across AWS Availability zones. Each zone is configured with Auto-Scaling that will scale-out based upon requests-per-target or CPU usage. It will likewise scale-in to reduce costs when not utilized.
Each availability zone uses Fargate as the capacity provider, along with the Amazon Elastic Container Service (ECS) as the orchestration service for the Mura Docker containers. Fargate Spot can also be utilized to provide a low-cost option for fault tolerant applications.
Each zone contains an access point to the Elastic File Server, and ElastiCache is used to provide persistent Session storage, allowing for seamless scale-in and scale-out events.
Aurora Serverless is used to provide automatic failover and automatic scaling based on application load (based upon MySQL 5.6 or 5.7). 
Public Network
Amazon CloudFront is the public-facing, global-distribution CDN for the VPC, with Mura and its assets as the origin. This insures low latency, high resiliency and high transfer speeds across all locales. 
Behind this is the public subnet. An Elastic Load Balancer using the AWC Certificate Manager to provide secure connections across the redundant availability zones. A NAT gateway provides outgoing access for the Mura containers. The “Bastion” jump host provides direct access for operations or the server management team (see Private Network, below).
Private Network
 The private network is placed across multiple availability zones to provide high availability and redundancy.
Bastion (aka “jump”) servers act as an extra layer of security by keeping containers isolated from the public internet. Direct access to containers by server operations or management can be achieved via the Bastion host. It can also be configured to allow access via other AWS services such as AWS Direct Connect or AWS Client VPN connection.

If needs increase to support additional traffic, storage or data transfer, there will be additional costs charged to Western Health Advantage based on usage. Mura will notify Western Health Advantage if this occurs, invoice accordingly and review options.

Current pricing for additional traffic per month (prices subject to change)