π [Open-Source] Strapi Node.js Headless CMS π
![π [Open-Source] Strapi Node.js Headless CMS π](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1665478901979%2FbxKkiPyF5.png&w=3840&q=75)
Search for a command to run...
![π [Open-Source] Strapi Node.js Headless CMS π](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1665478901979%2FbxKkiPyF5.png&w=3840&q=75)
No comments yet. Be the first to comment.
Modern-Apps are built with modular architectural patterns, Serverless operational models, Agile developer processes. To innovate faster, reduce risk, accelerate time to market, and decrease your TCO.
π― Implementing Headless Architecture for Content Management System (CMS) using Jamstack (JavaScript, APIs, and Markup) and Cloud Hosting (Gatsby Cloud, Netlify, AWS Amplify) β‘ π Live Demo: https://academy.job4u.io/ π₯οΈ The cloud journey generally ...
[Internal Press Release] Today we announce the general availability of ADLC (Agent Development Lifecycle) Framework v1.3.0, an open-source enterprise governance framework for AI-powered CloudOps, DevSecOps, and FinOps automation. π The Problem C...
Hybrid Testing Strategy π° ROI: 35% Velocity β and 90% Cost Reduction
Comprehensive Network Analysis of Enterprise Central Network Hub using Production-Ready Enterprise-Grade Agent SDLC Framework
π₯ Efficient Agile SDLC Workflow to build & publish Runbooks PyPI π₯
Part 1. AWS Architecture Diagram

β¬οΈSkills to build and run Modern Applications β‘ using Open-Source π, Cloud-Native π₯οΈ and Data Analytics π₯.
14 posts
π₯ Agentic AI Enterprise Applications focus on autonomously achieve complex business goals, rethinking workflows with Agentic AI, and driving business value through cost, quality, speed, and scale. β‘
π― An Open-Source NodeJS-based Content Management System with a fully customizable API. You can save time and effort by creating production-ready Node.js APIs in hours rather than weeks. π
π― Deliverables:
DockerfileDockerfile.proddocker-compose.ymlπ₯οΈ The cloud journey generally involves migrating and modernizing websites and apps, including building and hosting websites, developing web and mobile apps, and monitoring and managing them. This hands-on series illustrates how to build a production-ready Headless CMS and Headless eCommerce using Jamstack (stands for JavaScript, API, and Markup) on Cloud (Heroku, AWS ...).
The Strapi Headless CMS is an Open-Source, Node.js platform for creating, managing, exposing and sharing content-rich experiences.
Traditional or monolithic Web-first CMS, such as WordPress, combine the frontend (website design and layout) and backend (the interface for editing and creating content) into a single application. The next-generation Content-first Headless CMS use an API for content delivery and allow complete separation of the backend (creation and storage) and frontend (design and deployment). Headless architecture not only rewards better performance and flexibility but also provides stronger security by making it nearly impossible for end-users to access the backend.

Developers are free to focus on designing amazing frontends that meet the needs of their customers because of all these benefits.
π¦ Prerequisites
Option 1. Git clone from https://github.com/OceanSoftIO/cms-blog.git
git clone https://github.com/OceanSoftIO/cms-blog.git
cd cms-blog
Option 2. Install Strapi CMS Backend with the blog schema template outside of the frontend directory on your machine.
echo "Strapi V4 template: https://github.com/OceanSoftIO/cms-blog/tree/main/template"
yarn create strapi-app backend --quickstart --template strapi-blog
echo "Strapi V3 OLD-version !!!"
# yarn create strapi-app cms --quickstart --template https://github.com/OceanSoftIO/cms-blog
Following the installation, Strapiβs control panel will open in your browser, where you can register the admin user and create content.
cd cms-blog/backend
yarn install
yarn develop
π http://localhost:1337/admin
Developers are faced with the task of launching a development environment that has different software packages of certain versions. Fortunately, Docker solves this problem in the modern development world.
Creating
Dockerfile&docker-compose.yml
# cd cms-blog/backend
# cat Dockerfile
# cat docker-compose.yml
π³ Creating a new
Dockerfile: If you are using YARN, please use the following π
FROM node:16
## Installing libvips-dev for sharp Compatability
RUN apt-get update && apt-get install libvips-dev -y
# FROM node:16-alpine
## Installing libvips-dev for sharp Compatability
# RUN apk update && apk add build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
π³ Optimizing your
Dockerfileβ οΈ, then please use the following π
The following are the methods by which we can achieve docker image optimization.

FROM node:16-alpine as build
## Installing libvips-dev for sharp Compatability
RUN apk update && apk add build-base gcc autoconf automake zlib-dev libpng-dev vips-dev && rm -rf /var/cache/apk/* > /dev/null 2>&1
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
FROM node:16-alpine
RUN apk add vips-dev
RUN rm -rf /var/cache/apk/*
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/app
COPY --from=build /opt/node_modules ./node_modules
ENV PATH /opt/node_modules/.bin:$PATH
COPY --from=build /opt/app ./
EXPOSE 1337
CMD ["yarn", "start"]
Quick tour of Dockerfile: π
π³ To get started, let's take a quick tour of Dockerfile: π
node:16 (~330 MB) or node:16-alpine (~39 MB) as our base image. libvips-dev for sharp compatibility, with -y, so say yes to everything. development by default so we don't have to provide this each time. development to production./opt WORKDIR working folder inside our container.yarn install installs all dependencies.cms-backend, into this folder.yarn build to build our MEAN project.1337 and tell Docker to run yarn develop.dockerignore π
π³ Docker Ignore: Create a file called
.dockerignore: π
.tmp/
.cache/
public
.git/
build/
node_modules/
data/
βοΈ These folders in .dockerignore will be skipped βοΈ by Docker π³ since they are not necessary.
docker build -t cms-backend:latest .
cms-backend, and it's tagged with :latestdocker system prune --all --force
docker run -d -p 1337:1337 cms-backend
-d means detached and is a fancy way of saying "Runs in the background"Tip: To use strapi on another port while developing, change the first part of the run port.
docker run -d -p 8888:1337 cms-backend
run on port 8888 π
βοΈ We are currently using an SQLite database, which is always inside the container. Whenever we stop a container, we lose all changes. Using
docker-compose, we can use a Postgres database and run multiple instances of Docker if needed.
docker-compose for the next levelβ¬οΈ https://github.com/Academy4U/docker/blob/docker/strapi/README.Strapi.md
πͺ Think of docker-compose as a way to make different steps or services that we want to run.
π https://github.com/Academy4U/docker/blob/docker/strapi/strapi/docker-compose.yml
config/database.js
βοΈ
config/database.jsπ
const path = require('path');
// module.exports = ({ env }) => ({
// connection: {
// client: 'sqlite',
// connection: {
// filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '.tmp/data.db')),
// },
// useNullAsDefault: true,
// },
// });
/** PostgreSQL Database */
module.exports = ({ env }) => ({
connection: {
client: env("DATABASE_CLIENT", "postgres"),
connection: {
host: env("DATABASE_HOST", "127.0.0.1"),
port: env.int("DATABASE_PORT", 5432),
database: env("DATABASE_NAME", "cms"),
user: env("DATABASE_USERNAME", "cms"),
password: env("DATABASE_PASSWORD", "cms"),
},
debug: false,
},
});
.env
.env πenv
HOST=0.0.0.0
PORT=1337
...
DATABASE_HOST=localhost
DATABASE_PORT=5432
# DATABASE_PORT=3306
DATABASE_NAME=cms
DATABASE_USERNAME=cms
DATABASE_PASSWORD=cms
NODE_ENV=development
DATABASE_CLIENT=postgres
# DATABASE_CLIENT=mysql
π³ In the root of the project, create a file called
docker-compose.yml. Due to the YAML format, spacing matters, so I've used spaces rather than tabs π
version: "3"
services:
cms:
container_name: cms
build: .
image: cms:latest
restart: unless-stopped
env_file: .env
environment:
DATABASE_CLIENT: ${DATABASE_CLIENT}
DATABASE_HOST: cmsDB
DATABASE_NAME: ${DATABASE_NAME}
DATABASE_USERNAME: ${DATABASE_USERNAME}
DATABASE_PORT: ${DATABASE_PORT}
JWT_SECRET: ${JWT_SECRET}
ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
NODE_ENV: ${NODE_ENV}
volumes:
- ./config:/opt/app/config
- ./src:/opt/app/src
- ./package.json:/opt/package.json
- ./yarn.lock:/opt/yarn.lock ##Replace with package-lock.json if using npm
- ./.env:/opt/app/.env
ports:
- "1337:1337"
networks:
- cms
depends_on:
- cmsDB
cmsDB:
image: postgres:12.0-alpine
container_name: cmsDB
platform: linux/amd64 ##for platform error on Apple M1 chips
restart: unless-stopped
env_file: .env
environment:
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: ${DATABASE_NAME}
volumes:
- cms-data:/var/lib/postgresql/data/ ##using a volume
#- ./data:/var/lib/postgresql/data/ ##if you want to use a bind folder
ports:
- "5432:5432"
networks:
- cms
volumes:
cms-data:
networks:
cms:
name: cms
driver: bridge
π I'll explain what all of this means: π
version - Docker-compose version 3services - We are defining two services cms and cmsDBcms - The name of the service we definedcontainer_name - The name of the container. You can call it whatever you want.build - Telling cms to build the image in our project folder ..image - The image name we want to buildrestart - Unless we STOP or take down the container, it will keep restarting.env_file - Providing a .env file containing the environmental variables we should keep secret. environment - Here we define all the variables we want to use. Our .env file will have $[THISISOURNAME] as a placeholder.volumes - mounting files into the container. Now this could be ./:/opt/app, but we might want to develop locally and just run our development server locally we are binding folders and some files to not bind node_modules There is some info about that here. ports - What ports we want to expose. Note: You can change the left side to another port, such as 8080:1337, but remember that the right side needs to be 1337, which is the port inside the container where CMS is running.networks - Set up a docker network so that our containers can communicate together. The Docker-Network tells Docker that before running the cms container, we need to run the postgresDB container first. This saves us some errors when we start the CMS container without a database.
Similarly, we give Postgres a name, but we use the official postgres:12.0-alpine image instead of building it ourselves. In addition, we are creating a volume called cms-data to hold our database.
βοΈ When installing Docker Desktop for MacOS, docker-compose is also automatically installed; however, for Linux, you must separately install it.
[ ] π³ Local: This will now spin up just a Postgres database, and we can run and change files just like working on Strapi anywhere.
docker-compose up -d cmsDB && yarn develop
[x] π³ Full: This will run Strapi inside a Docker Container and the database in its own container.
docker-compose up -d
AWSAWS AmplifyAWS App Runner || ECS/EKS using Terraform and AWS CodePipeline