Cristian Rita FullStack Engineer πŸ‘¨πŸ»β€πŸ’» | Teacher | Follow me on twitter.

Running Strapi in production with AWS

5 min read 1481

Running Strapi in Production with AWS

Introduction

Strapi is one of the most popular open-source headless CMSes with more than 39k Github stars. Currently, you have to host Strapi on your infrastructure because the cloud version is not yet available. The good news is that there are plenty of options available. In this article, I will discuss running Strapi on AWS in Production.

Strapi documentation has, already, an in-depth tutorial on how to host it on AWS. However, that is not production-grade, so I am going to cover the missing parts here.

First, let’s see what you require to run Strapi in Production:

  1. compute capacity β€” you need something that runs our app, a server;

  2. database β€” Strapi saves the content into an SQL or NoSQL database;

  3. storage β€” you have to store the media files somewhere;

  4. monitoring β€” collecting and viewing application logs is crucial in a production environment;

  5. secret management β€” you need to handle access keys, passwords, etc.;

  6. scalability β€” the system should be easy to scale

1. Compute capacity

EC2

The obvious solution is to run the application on an AWS EC2 instance. t2.small is the smallest instance type that can run Strapi.

When you launch an EC2 instance, you need to choose an AMI. An AMI is a template that contains the operating system and the software required to launch the instance. I suggest using Amazon Linux 2 as it makes it easy to integrate with other AWS services.

Another important thing to set up is the security group, which acts as a firewall and lets you control the inbound and outbound traffic.

N.B., do not allow SSH from anywhere! SSH access should only be allowed from your internal, secure network.

Once the instance is running, you should be able to access it via ssh. Strapi being a Node.js application, you need to make sure Node is installed. Unfortunately, Amazon Linux 2 comes with an old version of Node that is not supported by Strapi. I recommend using NVM for managing different versions of Node.

Using the following snippet, you can install the latest version of Node:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
. ~/.nvm/nvm.sh
nvm install node

Now that you have NPM available, you should also install PM2, a process manager that will help you manage your application.

We made a custom demo for .
No really. Click here to check it out.

If you decide to go with an EC2 instance, you should also have a look at Reserved Instances because they can reduce the costs significantly.

Containers

Another popular solution is to run Strapi using containers. AWS has a bunch of services for managing and running containers. They can be classified into 3 categories:

  • Registry: AWS ECR(Elastic Container Registry) β€” this helps you manage and store container images;
  • Orchestration: AWS ECS (Elastic Container Service), AWS EKS (Elastic Kubernetes Service) β€” these services allow you to configure how the containers should run;
  • Compute: AWS Fargate, AWS EC2, AWS App Runner β€” the underlying computing layer;

Here is the official Docker image for Strapi.

When it comes to orchestration, choosing between AWS ECS or AWS EKS is really up to you. If you are already using Kubernetes, or you like the flexibility they provide, EKS is the right tool for you. On the other hand, ECS is the AWS-opinionated solution for running containers and thus it’s easier to start with and it better integrates with other AWS services.

Next, you need to decide where to run your containers. Similarly, this is a matter of flexibility. Fargate is a serverless container compute engine. It’s useful because you don’t have to take care of the underlying environment as required when using EC2.

I would use ECS and Fargate for the simplicity they provide.

2. Database

By default, Strapi connects to an SQLite database. As this is not suitable for production, you need to choose between PostgreSQL, MySQL, MariaDB, and MongoDB.

N.B., MongoDB is no longer supported in Strapi V4.

If you want, you can deploy your database server on an EC2 machine, but I highly recommend using AWS RDS because it eliminates the complexity of configuring, scaling, and backing up a database.

Creating a database on RDS is straightforward, but remember that you should only allow the traffic coming from your Strapi application to connect to the database. So the Public access option should be set to No. You will need to configure a security group rule to allow inbound traffic from your EC2 security group.

Strapi keeps the database configuration file under config/database.js. If you need to have different configurations in development and production, database configs can be created per environment under:

config/env/{env_name}/database.js

3. Storage

Storing assets into a relational database, while possible, is not a good idea. For managing media files, Strapi is using upload providers. The default provider is saving files to a local directory under the ./public/uploads folder. There are a lot of providers available.

AWS S3 is a great service for storing files and there is a provider built for this. You can install it from npm:

npm install strapi-provider-upload-aws-s3

One thing that I do not like about this plugin is that it is adding an ACL rule that is making the S3 bucket publicly accessible. For many users, this is not acceptable, so I made a fork and removed that ACL rule. You can find my version of the provider here.

Now you need to allow your application to write to that S3 bucket. For this, I recommend using IAM roles for EC2.

4. Monitoring

In a production environment, it is crucial to monitor both your application and your AWS resources. This can be achieved using AWS CloudWatch.

If you run Strapi on an EC2 machine or a Docker container you will need to install the CloudWatch agent. The agent sends metrics and logs to CloudWatch. On Amazon Linux 2 it is available as a package:

sudo yum install amazon-cloudwatch-agent

By default, the agents send a series of metrics to CloudWatch. I won’t cover here how you configure the agent, but the following links should be helpful:

5. Secret Management

Keeping passwords and configurations in a centralized place and securely referencing them from your application can be tricky. As you probably expect, AWS has a service for this: System Manager Parameter Store. Parameter Store is a key-value store where you can keep passwords, database strings, access keys, etc. either as plain text or encrypted. It integrates with both EC2 and ECS.

Let’s consider the database config file:

  // ./config/database.js
    module.exports = ({ env }) => ({
      defaultConnection: "default",
      connections: {
        default: {
          connector: "bookshelf",
          settings: {
            client: "postgres",
            host: env("DATABASE_HOST", "localhost"),
            port: env.int("DATABASE_PORT", 5432),
            database: env("DATABASE_NAME", "strapi"),
            username: env("DATABASE_USERNAME", "postgres"),
            password: env("DATABASE_PASSWORD", "secret"),
            schema: env("DATABASE_SCHEMA", "public"),
          },
          options: {},
        },
      },
    });

You can keep every parameter like DATABASE_HOST, DATABASE_PORT, DATABASE_NAME, DATABASE_USERNAME, DATABASE_PASSWORD, DATABASE_SCHEMA in Parameter Store. Using AWS CLI you can fetch the parameters from Parameter Store like this:

aws ssm get-parameters \
    --names "DATABASE_HOST" "DATABASE_PORT" "DATABASE_NAME" "DATABASE_USERNAME" "DATABASE_PASSWORD" "DATABASE_SCHEMA"

The response should be something like:

{
    "Parameters": [
        {
            "Name": "DATABASE_HOST",
            "Type": "String",
            "Value": "localhost",
            "Version": 1,
            "LastModifiedDate": 1582154764.222,
            "ARN": "arn:aws:ssm:us-east-1:111222333444:parameter/DATABASE_HOST"
            "DataType": "text"
        },
        {
            "Name": "DATABASE_PORT",
            "Type": "String",
            "Value": "5432",
            "Version": 3,
            "LastModifiedDate": 1582156117.545,
            "ARN": "arn:aws:ssm:us-east-2:111222333444:parameter/DATABASE_PORT"
            "DataType": "text"
        },
.....
    ]
}

When I launch the instance, I usually run a tiny script that is querying the Parameter Store, parses the JSON response, and exports the parameters as environment variables in my .env.production file.

6. Scalability

Usually, every AWS service is capable of scaling when needed. The only thing this infrastructure is missing is an ALB (Application Load Balancer) in front of the application. There are multiple reasons why an ALB is beneficial:

  • it isn’t good practice to keep the application at the edge of the network;
  • you can always add multiple instances/containers when needed;
  • Strapi doesn’t support HTTPS;
  • necessary for blue/green deployments

Also, when running your application on EC2, you should consider using an EC2 autoscaling group. An autoscaling group consists of one or more EC2 instances. You specify the minimum, the maximum, and the desired number of instances.

Let’s say you set the minimum to 1, desired to 1, and the maximum to 3. First, the autoscaling group will launch 1 instance as this is the desired number. Then, in case of a spike, it will launch more instances, but no more than 3. When the demand drops, it will terminate the unnecessary instances but will keep at least one.

Conclusion

There are a lot of decisions to make when deploying Strapi on AWS. It can be a bit overwhelming, especially if you are new to AWS. I hope this article will serve as a starting point and will give you a high-level overview of what it takes to run Strapi in Production on AWS.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Cristian Rita FullStack Engineer πŸ‘¨πŸ»β€πŸ’» | Teacher | Follow me on twitter.

Leave a Reply