Building A High-Performance Decoupled CMS In AWS
Building A High-Performance Decoupled CMS In AWS
Web Content Management Systems
From the inception of the World Wide Web (www), websites and pages were a popularly adopted concept in the digital world whether it was for used for commercial, government, research or community purposes.
Making websites more interactive and useful for daily transactions led to implementation of dynamic websites which were developed in either in a high-level programming language such as PHP, Java or JavaScript. As the need of having an online presence surged, the pain of developing feature rich web applications increased as it involved different software frameworks and coding. That is where Web Content Management Systems came to the rescue for easily creating and managing content.
- Speed and performance of a website with that of a similar competitor matter, and users will move if they are dissatisfied.
- Website contents include high-definition media (images, animation, videos, audio etc.) that should be delivered without any delay.
- End user devices (clients) are becoming more than just a presentation platform and their processing capabilities should be leveraged rather than doing processing on the server-side.
- With the wide adoption of public cloud, there are more ways to host web applications, be it static webhosting, serverless, or container based microservices. They can be made very secure and costs less as well.
IANCON Technologies is an AWS Advanced Consulting Partner for both Commercial and Public Sector. With vast experience in migrations and modernization of legacy infrastructure and applications, we can help you move to the cloud.
Decoupled CMS with Frontend WebApp and a Headless CMS
WordPress, Joomla, Drupal etc. fall into the category of traditional CMS. In order to improve speed and performance, the best option would be to decouple the ‘head’ (the frontend) from the ‘body’ (backend processing / content management) and integrate them with an API, i.e., run the CMS headless and have the frontend as a progressive web application with a JS framework of your choice.
- GraphQL responses are typed & organized – it can support complex object & data types like json scalars, enumerations, unions, interfaces and supports nullability. It helps fetch a wide variety of data from the CMS and the requesting app can use types to avoid writing manual parsing code.
- GraphQL queries always return predictable results. There is no under or over utilization of the API request. Apps using GraphQL are fast and stable because they control the data they get rather than the server. This leads to less time in generating the static site files.
- GraphQL APIs can get all the required data in a single request, while typical REST APIs require loading from multiple URLs. GraphQL queries access not just the properties of one resource but smoothly follows references between them.
- Integrating GraphQL with GatsbyJS and CMS(eg: WordPress, Drupal) is easy with community developed packages and plugins.
Architecting the solution in AWS
- Security
- Reliability
- Operational Excellence
- Performance Efficiency
- Cost Optimization
AWS Infrastructure
Drupal 8 as Headless CMS
Automated Deployment Pipeline
Deployment automation of Frontend website with S3 Static Webhosting
Similar to the Drupal8 CMS deployment pipeline, we will have another pipeline for the frontend. However, we need to configure the Amazon Code Build buildspec.yml (build specification/configuration) so that build process can be automated without requiring a continuously running build server. The build logs can be populated in a CloudWatch log stream or written to a S3 bucket, to help with debugging in case of any issues. Here is an example buildspec.yml:
version: 0.2
run-as: root
phases:
install:
runtime-versions:
nodejs: 10
python: 3.7
commands:
- "echo \"### Entered the install phase...#####\""
- "node -v"
- "npm -v"
- "python --version"
- "aws --version"
- "echo Default Linux shell is `ps -p $$`"
- "echo \"Installing all dependencies as per package.json\""
finally:
- "npm install"
pre_build:
commands:
- "echo \"### Entered the pre_build phase...#####\""
- "echo \"List of installed dependencies:\""
- "npm list -g"
- "echo \"### Initiating the build...#####\""
- "echo Build started at `date`"
- "npm run build && export static_web_build_stat=\"PASS\""
finally:
- "echo ${static_web_build_stat}"
- "echo Build ended at `date`"
build:
commands:
- "echo \"### Entered the build phase...#####\""
- "echo \"### Removing .map files from the build...#####\""
- "find ./public -name '*.map' -type f -delete"
- "echo \"### Deploying the built code to S3 bucket...#####\""
- "aws s3 sync \"public\" \"s3://prod-frontend-s3website/\" --region eu-west-1 --delete"
- "aws s3 sync \"public\" \"s3://prod-frontend-s3website2/\" --region me-south-1 --delete"
finally:
- "echo \"Deployed site to S3\""
post_build:
commands:
- "echo \"### Entered the pre_build phase...### \""
- "echo \"Initiating CloudFront invalidation\""
- "aws cloudfront create-invalidation --distribution-id YORB6XXXRPDD --paths '/*'"
- "echo \"Invalidation completed\""
finally:
- "echo Deployment ended at `date`"
artifacts:
base-directory: public
discard-paths: "no"
files:
- "**/*"
The resulting artifacts will be the ReactJS static website with html, js, cs, fonts etc. This should be synced to two S3 buckets in different regions as a deployment. This will ensure site availability even in case of an AWS region being unavailable.
Improving the site performance with AWS CloudFront
The S3 static website can directly be used to serve the website. However, we can serve the site as a Progressive Web Application (PWA) through Amazon CloudFront.
A CloudFront web distribution with custom SSL certificate for the domain has to be created. We create three origins – one for the ALB for dynamic requests and two custom origins, one for each of the S3 static web hosting endpoints (say, Ireland and Singapore buckets). Create an origin group with the two S3 static web hosting endpoint origins to provide re-routing during a failover event. We can associate an origin group with a cache behavior to have requests routed from a primary origin to a secondary origin for failover. Something to note - we must have two origins for the distribution before we can create an origin group.