Skip to content

whatthehanan/deploy-strapi-on-aws

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 

Repository files navigation

Deploying a Strapi API on AWS (EC2 & RDS & S3)

Goal: build a HTTPS-secured Strapi API with dev & staging & prod modes

Everything done in the following is AWS Free Tier eligible.
Make sure you have already skimmed the Strapi docs before you start.

§ Create EC2 instance / RDS instance / S3 bucket

You can skim this section if you are familiar with AWS

⊙ EC2

  1. Click Launch Instance button
  2. Choose AMI: Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
  3. Choose Instance Type: General purpose, t2.micro
  4. Configure Instance: as you like
  5. Add Storage: General Purpose SSD (gp2), 8 GB
  6. Add Tags: as you like
  7. Configure Security Group:
    • SSH (22) - My IP or Anywhere or as you like
    • HTTP (80) - Anywhere
    • HTTPS (443) - Anywhere
  8. Review: click Launch button, then a modal pops up. If you are a:
    • Newbie: Choose Create a new key pair named strapi-cms, download it as strapi-cms.pem
    • Veteran: as you like
  9. Finally, click Launch Instances button

⊙ RDS

  1. Click Create database button
  2. Select engine: PostgreSQL
  3. Choose use case: as you like
  4. Specify DB details:
    • DB engine version: PostgreSQL 10.x-R1
    • DB instance class: db.t2.micro
    • Multi-AZ deployment: No
    • Storage: General Purpose (SSD), 20 GB
    • DB instance identifier: as you like
    • Master username: as you like
    • Password: as you like, recommend https://passwordsgenerator.net
  5. Configure advanced settings
    • Public accessibility: Yes (that's why you need a super strong password)
    • Database name: strapi
    • Monitoring & Maintenance window: choose an idle peroid in your timezone
    • Click Create database button
  6. Instance Details panel - Security groups
    • Edit inbound rules: PostgreSQL (5432) - Anywhere
  7. Create databases for dev & staging modes (GUI recommend: https://dbeaver.io)
    • Development mode: strapi_dev
    • Staging mode: strapi_staging
    • Production mode: strapi (already exists)

⊙ S3

  1. Click Create bucket button
  2. Name and region
    • Bucket name: as you like
  3. Configure options: as you like
  4. Set permissions
      • Block new public ACLs and uploading public objects (Recommended)
      • Remove public access granted through public ACLs (Recommended)
      • Block new public bucket policies (Recommended)
      • Block public and cross-account access if bucket has public policies (Recommended)
    • Do not grant Amazon S3 Log Delivery group write access to this bucket
  5. Review: click Create bucket button

§ Point your domain to EC2

Point the A / CNAME records to the EC2's IPv4 Public IP / Public DNS (IPv4), such as:

  • Development mode: dev-cms.yourdomain.com
  • Staging mode: staging-cms.yourdomain.com
  • Production mode: cms.yourdomain.com

§ Warm up EC2

⊙ Login to EC2 & update

Switch to the directory where the key pair strapi-cms.pem locates:

$ ssh -i strapi-cms.pem ubuntu@<ec2-public-ip>
$ sudo apt update

⊙ Install Nginx

$ sudo apt install nginx

⊙ Install nvm & Node.js & PM2

  • Install nvm:
    $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
  • Install Node.js:
    $ nvm install 10
  • Install PM2:
    $ npm i pm2 -g

⊙ Install Certbot

According to https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx :

$ sudo apt-get install software-properties-common
$ sudo add-apt-repository universe
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx

§ Create a local Strapi project

⊙ Installation and initialization

Firstly, install Strapi (refer to https://strapi.io/documentation/3.x.x/getting-started/installation.html):

$ npm i -g strapi@alpha

Secondary, create a new project (refer to https://strapi.io/documentation/3.x.x/cli/CLI.html#strapi-new):

$ strapi new strapi-cms \
    --dbclient=postgres \
    --dbport=5432 \
    --dbhost=<RDS endpoint> \
    --dbname=strapi_dev \
    --dbusername=<RDS master username> \
    --dbpassword=<RDS password>

Finally, DO NOT rush to strapi start for now.
There are some preparatory procedures to accomplish.
(By the way, you may be interested in https://strapi.io/documentation/3.x.x/advanced/usage-tracking.html)

⊙ Complete database configuration

If you prefer best practices like https://12factor.net/config and https://github.com/i0natan/nodebestpractices/blob/master/sections/projectstructre/configguide.md , you'd better use tools like dotenv instead.

strapi-cms/config/environments/development/database.json has been completed during the initialization.
Complete strapi-cms/config/environments/{staging|production}/database.json based on it. For example:

{
  "defaultConnection": "default",
  "connections": {
    "default": {
      "connector": "strapi-hook-bookshelf",
      "settings": {
        "client": "postgres",
        "host": "<RDS endpoint>",
        "port": 5432,
        "database": "<strapi_staging|strapi>",
        "username": "<RDS master username>",
        "password": "<RDS password>"
      },
      "options": {
        "ssl": false
      }
    }
  }
}

⊙ Fix listening ports

Modify port in strapi-cms/config/environments/{staging|production}/server.json:

  • development: 1337 (default)
  • staging: 1338
  • production: 1339

⊙ Install S3 upload plugin

Refer to https://strapi.io/documentation/3.x.x/guides/upload.html#install-providers

$ npm i -S strapi-provider-upload-aws-s3@alpha

⊙ Add npm scripts for staging & production mode

You can use PM2 - Ecosystem File instead if you'd like to

npm start is for development mode by default.
You can set NODE_ENV before it according to https://strapi.io/documentation/3.x.x/guides/deployment.html .
However, for the sake of compatibility, cross-env is introduced.

$ npm i -D cross-env

So strapi-cms/package.json may look like:

{
  ...
  "scripts": {
    "setup": "cd admin && npm run setup",
    "start": "node server.js",                         // for development mode
    "staging": "cross-env NODE_ENV=staging npm start", // for staging mode 
    "prod": "cross-env NODE_ENV=production npm start", // for production mode
    "strapi": "node_modules/strapi/bin/strapi.js",
    "lint": "node_modules/.bin/eslint api/**/*.js config/**/*.js plugins/**/*.js",
    "postinstall": "node node_modules/strapi/lib/utils/post-install.js"
  },
  ...
}

⊙ Add nginx.conf to the project root

If you prefer best practices using /etc/nginx/{sites-available|sites-enabled}, you may need help from https://nginxconfig.io or https://github.com/h5bp/server-configs-nginx . I prefer single file nginx.conf because of simplicity.

Don't forget to replace all yourdomain.com with yours.

⊙ Run

$ cd strapi-cms && strapi start

Your browser will open http://localhost:1337 automatically later.
Create the admin with a strong password.

⊙ Complete S3 settings

Visit PLUGINS > Files Upload to complete the S3 settings for all modes.

⊙ GraphQL

If you'd like to equip GraphQL, visit GENERAL > Marketplace to download.
Refer to https://strapi.io/documentation/3.x.x/guides/graphql.html for further info.

⊙ Configure response & security

Since Strapi will be running behind a well-tuned Nginx, you should:

For more details, please turn to https://strapi.io/documentation/3.x.x/configurations/configurations.html

⊙ Push to a Github free private repo (or Gitlab, etc)

$ git init
$ git add -A
$ git commit -m 'init'
$ git remote add origin <private-git-repo-url>
$ git push -u origin master

§ Deploy Strapi on EC2

⊙ Pull the repo and install npm dependencies

$ cd ~
$ git clone <private-git-repo-url>
$ cd strapi-cms
$ npm i

⊙ Run all modes with PM2

Thanks to this Stack Overflow comment, you can run npm scripts with PM2:

$ pm2 start npm --name "strapi-dev" -- start
$ pm2 start npm --name "strapi-staging" -- run staging
$ pm2 start npm --name "strapi-prod" -- run prod

Also, you need to set up the PM2 Startup Hook in case of reboot:

$ pm2 startup
$ pm2 save

You can check if the startup hook works by rebooting the machine if you'd like to:

$ sudo reboot

$ ssh -i strapi-cms.pem ubuntu@<ec2-public-ip>
$ pm2 ls

⊙ Replace /etc/nginx/nginx.conf with yours

$ cd ~/strapi-cms
$ sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
$ sudo cp nginx.conf /etc/nginx/nginx.conf

⊙ Obtain SSL certificates

According to https://nginxconfig.io :

# HTTPS - certbot (before first run): create ACME-challenge common directory
$ sudo mkdir -p /var/www/_letsencrypt && chown www-data /var/www/_letsencrypt

# HTTPS - certbot (before first run): disable SSL directives
$ sudo sed -i -r 's/(listen .*443)/\1;#/g; s/(ssl_(certificate|certificate_key|trusted_certificate) )/#;#\1/g' /etc/nginx/nginx.conf

# Reload Nginx config
$ sudo systemctl reload nginx

# HTTPS - certbot: obtain certificates
$ sudo certbot certonly
    --webroot -n --agree-tos --force-renewal \
    -w /var/www/_letsencrypt \
    --email <your-email> \
    -d cms.<yourdomain.com> \
    -d staging-cms.<yourdomain.com> \
    -d dev-cms.<yourdomain.com>

# HTTPS - certbot (after first run): enable SSL directives
$ sudo sed -i -r 's/#?;#//g' /etc/nginx/nginx.conf

# Reload Nginx config again
$ sudo systemctl reload nginx

All done! Visit https://{cms|staging-cms|dev-cms}.yourdomain.com to see if it works.

⊙ Further optimizations

§ Summary

Now you have:

  • A Strapi API running on dev & staging & prod mode simultaneously
  • PM2-guarded processes with reboot startup hooks
  • Forced HTTPS-secured traffic for all
  • Auto-renew SSL certificates for free

PRs & issues are welcome! Sharing your experience will save others' time! tip

About

Deploying a Strapi API on AWS (EC2 & RDS & S3)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published