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.
You can skim this section if you are familiar with AWS
- Click
Launch Instance
button - Choose AMI:
Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
- Choose Instance Type:
General purpose, t2.micro
- Configure Instance: as you like
- Add Storage:
General Purpose SSD (gp2), 8 GB
- Add Tags: as you like
- Configure Security Group:
- SSH (22) -
My IP
orAnywhere
or as you like - HTTP (80) -
Anywhere
- HTTPS (443) -
Anywhere
- SSH (22) -
- Review: click
Launch
button, then a modal pops up. If you are a:- Newbie: Choose
Create a new key pair
namedstrapi-cms
, download it asstrapi-cms.pem
- Veteran: as you like
- Newbie: Choose
- Finally, click
Launch Instances
button
- Click
Create database
button - Select engine:
PostgreSQL
- Choose use case: as you like
- 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
- DB engine version:
- 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
- Public accessibility:
- Instance Details panel - Security groups
- Edit inbound rules: PostgreSQL (5432) -
Anywhere
- Edit inbound rules: PostgreSQL (5432) -
- Create databases for dev & staging modes (GUI recommend: https://dbeaver.io)
- Development mode:
strapi_dev
- Staging mode:
strapi_staging
- Production mode:
strapi
(already exists)
- Development mode:
- Click
Create bucket
button - Name and region
- Bucket name: as you like
- Configure options: as you like
- 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
-
- Review: click
Create bucket
button
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
Switch to the directory where the key pair strapi-cms.pem
locates:
$ ssh -i strapi-cms.pem ubuntu@<ec2-public-ip>
$ sudo apt update
$ sudo apt install nginx
- 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
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
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)
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
}
}
}
}
Modify port
in strapi-cms/config/environments/{staging|production}/server.json
:
- development: 1337 (default)
- staging: 1338
- production: 1339
Refer to https://strapi.io/documentation/3.x.x/guides/upload.html#install-providers
$ npm i -S strapi-provider-upload-aws-s3@alpha
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 filenginx.conf
because of simplicity.
Don't forget to replace all yourdomain.com
with yours.
$ cd strapi-cms && strapi start
Your browser will open http://localhost:1337 automatically later.
Create the admin with a strong password.
Visit PLUGINS > Files Upload to complete the S3 settings for all modes.
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.
Since Strapi will be running behind a well-tuned Nginx, you should:
- Visit GENERAL > Configurations > ENVIRONMENTS > Response, set Production & Staging's Gzip to
OFF
- Visit GENERAL > Configurations > ENVIRONMENTS > Security, copy all the settings from Development to Production & Staging
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
$ cd ~
$ git clone <private-git-repo-url>
$ cd strapi-cms
$ npm i
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
$ cd ~/strapi-cms
$ sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
$ sudo cp nginx.conf /etc/nginx/nginx.conf
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.
- See https://strapi.io/documentation/3.x.x/guides/deployment.html
- Remove
strapi-cms/public/index.html
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!