Sitemap

Deploying Strapi Version 4, on Linode or any cloud host using PM2 via Github and accessing it from aSSL domain using Lets Encrypt and NGINX reverse proxy.

16 min readFeb 18, 2022

ARJUNA’S CODING JOURNAL:

I have started writing notes to myself when I code something and it works well, so that I can refer to it later. I figure in blog form they will also help others.

Recently I deployed Strapi Version 4, a headless Node and Javascript based CMS to my Linode server. I had to find my way through a jungle of tutorials and videos, as I did not find any clear or up to date instructions out there. These instructions should work for most cloud based servers where you have terminal SSH access.

It was not a straightforward and smooth experience, though it could have been because in retrospect it is very simple. The issue is that a lot of things are taken for granted by the writers of tutorials and makers of videos and there are some breaking changes between Strapi Version 3 and 4, rendering a lot of tutorials video and blog, out there obsolete. So for my own future reference and to help those who want to deploy Strapi to their own server I am writing this post.

Strapi could be a very useful part of the JAM stack which is a good way of thinking about how to create decoupled applications. You can use it to create APIs for your data easily. It also supports Graphql. Another very good feature is that you don’t have to do the boilerplate work for creating forms for data entry. It does a lot of the grunt work for you and you can simply then create front end applications that consume these APIs. I am using it with Next JS which is a React framework that generate static pages that are excellent for SEO.

HOW TO THINK ABOUT STRAPI DEPLOYMENT

Conceptually a Strapi deployment to the server is very similar to the Strapi deployed locally. To make it clear, the local and deployed production installation process only differs as follows:

  • When deploying locally you simply deploy from the terminal on your local machine and for production you SSH into your server and follow almost the same steps to deploy it to your production server. Then there is the additional work of pointing your domain to the strapi port on your production server. All of this is covered in this article.
  • The key difference between a local install and a production deployment is that when we run the local install we run it using the command npm run develop, whereas when we deploy for production on the server we run a npm run build command and start it up using npm run start. Also we use PM2 to manage the process on the server to ensure that it continues to run in a stable way.

Anyway don’t worry about that now all this will be covered in due course. The most important thing to know is that there is no black magic to deploying Strapi, its pretty much the same as installing it on the local machine with a few minor differences.

Another point to keep in mind is that if you search for Strapi deployment on Google or Youtube, there is a plethora of articles and videos on how to deploy Strapi to Heroku. However, think about it, if you are creating a Strapi headless CMS, you are likely to be using it to store data for your application, that is important to you or your clients and you will want this on your own server. Besides, Strapi is in development and in my case the install to Heroku simply broke and so deploying to Heroku is where the black magic is. The clean and straight path is to install it on your own Linode, or Digital Ocean droplet or AWS or whatever you use as for cloud hosting.

WHERE TO INSTALL

In this article we are first going to install Strapi on our local machine and then when it is up and running we will deploy it to the cloud based server using github. However please note that the server also has to have a supported version of Node and the database installed. Therefore you need to follow the following section PREPARING FOR INSTALLATION on both your local machine AND the server. This is done on the server, simply by using SSH to access a terminal on the server and then following the exact same steps as you are on the local machine. This assumes that your local machine and server are running a similar operating system though it does not have to be the same. In my case I am running Ubuntu 20.04 locally and Ubuntu 16.04 on my Linode server and everything worked like a charm.

PREPARING FOR THE INSTALLATION

The Strapi Documentation on installation states:

The CLI installation guide requires at least two software prerequisites to be already installed on your computer:

Node.js: only LTS versions are supported (v12 and v14). Other versions of Node.js may not be compatible with the latest release of Strapi. The 14.x version is most recommended by Strapi.

npm: (v6 only) or yarn to run the CLI installation scripts.

A database is also required for any Strapi project. Strapi currently supports the following databases:

Database Minimum version SQLite 3 PostgreSQL 10 MySQL 5.7.8 MariaDB 10.2.7

Check your node version

node -v

Strapi recommends that you use Node versions 14.x. You can use NVM, Node Version Manager to switch between different versions of node. I found that there is a Node 14.x LTS called Fermium. Here is an article on how to use NVM to switch between versions of node.

You should be using a 14.x version of node on your server at this stage.

The following command will show you the versions of node that you have installed.

nvm list
The result of node -v and then nvm list commands on my machine

So version 12.13.0 is selected. Since Strapi recommends that it works best with version 14.x and I have 14.18.3 installed, lets switch over to that as follows:

Switch to a 14.x version of Node

nvm use 14.18.3

Now we are using a compatible version of Node. Strapi fails to install even with a 12.x version of Node. Therefore switching to a 14.x version of Node is important.

Choosing a database

Strapi needs a database in the backend (Which we don’t really have to interact with once Strapi is installed or deployed) The local development version of Strapi uses SQL Lite by default. But it is recommended that another database be used for deployment. The following are supported.

A supported database version

  • MySQL >= 5.7.8
  • MariaDB >= 10.2.7
  • PostgreSQL >= 10
  • SQLite >= 3

Strapi Version 3 allowed you to use Mongodb. But Strapi Version 4 does NOT support Mongodb at this time. What is taken for granted in the documentation is that you must manually install the database you want Strapi to use.

For the local install the database included in the quick start, SQLLite, is fine, however since we cannot use that when deploying to the server, we will go with PostgreSQL for both the local and the deployment install.

Installing PostgreSQL

We can install PostgreSQL from a repository as follows:

  • Import the GPG repository key
sudo apt-get install wget ca-certificateswget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
  • Add the PostgresSQL repository
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
  • Update package list
sudo apt-get update
  • Install postgreSQL and postgreSQL contrib packages
sudo apt-get install postgresql postgresql-contrib
  • Connect to PostgreSQL
sudo su - postgres
  • Open Postgres prompt
psql
  • Check connection info (from within the postgres prompt)
\conninfo

Creating Database and User Credentials

From within the postgres-# prompt lets create a database. Choose a dbname, this will be the database that we will specify in the Strapi configuration and will be used by Strapi.

CREATE DATABASE dbname;

Don’t forget the semi-colon or posrgres does nothing. When done it spits out CREATE DATABASE.

Then create a User Role, which includes the user name and password for the database. db_user should be replaced with the user name that you want and a password you set.

CREATE ROLE db_user WITH LOGIN PASSWORD 'password' CREATEDB;

Postgres responds with CREATE ROLE.

If you want to check whether your database was created you can list all of the databases:

\l

If you want to check whether your user was created you can list all of the user roles:

\du

To quit the postgres=# prompt do:

\q

Note down the database name, user and password as we will have to add these to the Strapi database configuration.

Repeating on the server

We have to ensure that Node version 14.x and postgreSQL are also installed on the server. Further we have to create the posrtgreSQL database and user on the server in addition to the local machine.

Open a terminal on your server using SSH.

Repeat the instructions in this section PREPARING FOR INSTALLATION again, but this time on the server. At the end of this the local machine and server should have the same version of node running and a postgreSQL database and user with the same names set up.

INSTALL STRAPI ON YOUR LOCAL MACHINE:

This step is to be implemented on your local machine only. We will use Github to deploy it to your server later. As noted before the Node and PostgreSQL have to be installed on your local machine and server and the Postgre users have to be created on both also.

Once we have switched to Node version 14.x and have Postgres SQL installed we can proceed to install to Strapi Version 4, on our local machine as follows:

npx create-strapi-app@latest my-project

The installation process will present you an option Quickstart or Custom. Choose Custom, because we need to specify our database. Choose Postgres for the database.

When prompted leave the Host and Port values at the default suggested values. Enter the following values as created in Postgre SQL in the previous section:

  • Database name
  • User name
  • Password

As of Strapi version 4 please be sure to select No for SSL, because turning on SSL causes the install to fail. You can still access your Strapi API’s using SSL, this setting is for Strapi’s internal communication with the PostgreSQL database.

This configures Strapi to use the database and user credentials that we have created in PostgreSQL.

Press enter or click to view image in full size
Configuring the Database in the Strapi setup

TESTING THE STRAPI INSTALL

After Strap is installed successfully change directories into the newly created folder which contains your strapi app and then start Strapi in development mode just to test that it is working.

cd ndsislstrapideploynpm run develop

In the above you would change the folder name to the one that you chose when you created your Strapi application.

If Strapi opens up in your browser means that it is successfully installed on your local machine. In your terminal press CTRL C, to exit out of the Strapi Development process.

DEPLOYING STRAPI TO YOUR SERVER

Creating an entry point server.js to launch on server via PM2

To launch our application on the server and to keep it running we will use PM2 which is a process manager. PM2 requires a server.js file to be able to run node server.js instead of npm run start so we will create a ./server.js file as follows in the root of our application:

const strapi = require('@strapi/strapi');strapi().start();
Press enter or click to view image in full size
Create a file in the root of our application ./server.js to enable us to launch the application via PM2

Build Strapi locally or on the server

At this stage you have two options you can either build your Strapi project on the server or on the local machine and transfer it to the server via github. Which option you choose depends upon how much memory you have on your server. I have the basic Linode which costs $5 per month and it has only 1GB of RAM. However if you look at the prerequisites for Strapi Installation atleast 2 GB of RAM is required. Most of this RAM is used in the build process. When I tried to build my Strapi on the server I got an out of memory error. So I built it on my local machine and transferred the build folder to my server using github. If you have at least 2GB of RAM on your server, you can do the following build process on the server directly.

To build the Strapi for production do the following on your local machine:

NODE_ENV=production npm run build
Press enter or click to view image in full size
Build Strapi for production

Push the Strapi application to github

Push all of the files including the build folder to github:

Go to the .gitignore file in your root folder and comment out the build by putting a hash in front of it like so

Comment out build in the .gitignore file

This will ensure that you build folder will be uploaded to github.

Push your application to github. You need to login to your github account and create an application with the same name as your strapi application (It doesn’t need to be the same but lets keep it the same for the sake of clarity) If you don’t have a github account you should create one. Git is an important part of the contemporary development workflow.

Press enter or click to view image in full size
Create a new github repository
Press enter or click to view image in full size
Url for the newly created github repository

Once you have created your repository come back to the terminal on your local machine and do:

git init
git add .
git commit -m "first commit"
git branch -M main
//Replace the URL in the below command from the url listed in your newly created git repository.git remote add origin https://github.com/yourreponame/yourapplicaionname.git
git push -u origin main
Press enter or click to view image in full size
Application pushed to github

Our application has been pushed to github including the production build.

Clone the Strapi application on our server from github

Now that the application has been pushed upto github we can clone it onto our server.

SSH into your server so that you have access to a terminal on your server.

I have installed my application in the ./home/myusername directory on the server. You can choose where you want to install it, just ensure that the location has the appropriate permissions. In my case they did out of the box. Cd into the directory you want to install the application and do:

git clone https://github.com/xxx/yyyy.git

You will get the url from your github repository.

Press enter or click to view image in full size
Git clone the application to your server from github

Manually upload the .env file

Strapi creates a .env file in the root of the application which stores global variables like Host, Port, Application Keys and so forth. This file should not live on github as it contains data that should be secure. So it has to be uploaded manually. While in the root of your application of your local machine do:

scp ./.env johnsmith@206.802.239.89:/home/john/mystrapiapplication

Scp is a standard way to transfer files so you can research it if you are not familiar with it. But you are essentially transfering the .env file from the root of your application on your local machine to the root of your application on your server. You could use FTP or any other way to copy this file.

To check whether the .env file is uploaded on the server in your application directory do:

ls -a

This will show you the hidden files.

Install node modules on the server

To install node modules on the server, from the application directory do:

npm install

Start the Strapi application on the server using PM2

There are two ways to start processes using PM2. One is the simple way if you want to run a single process and this is what is detailed below. However if you have developed multiple applications and want to run them all on the server at the same time, you can create an ecosystem.config.js file. If you want to do this I have written a separate blog post on this which lives here. However this is not necessary to install Strapi and you can simply proceed as below:

To start the application on the server, from the application directory do:

pm2 start node server.js --name nameofyourapplication

To see the status of your application do:

pm2 status

You should get a status showing that your application is online as follows:

Press enter or click to view image in full size
Strapi application online on the server

If for any reason you see errored in the status don’t panic it is likely somthing small that you may have missed. Simply start the application without PM2 so that you can see the precise error message which you can use to debug.

node server.js

Only do the above you have an errored status and you want to see the error message to debug it.

At this stage your Strapi application should be deployed and running on the your server. If you go to your browser and type in:

yourserveripaddress:1337

You should see a message stating that your Strapi server is running successfully.

Press enter or click to view image in full size
Strapi server is running successfully

SETTING UP CONTENT TYPES

When we run Strapi on the server by doing pm2 start node server.js — name nameofyourapplication we are deploying Strapi for production. A production deploy does not allow us to set up Content Types. To do this we can stop the production deploy by doing

pm2 stop nameofyourapplication

And then simply running

npm run develop

on the server. Now we can user the Strapi admin console to set up our content types and our Strapi application. When we are done we can again deploy the application for production by doing:

pm2 start node server.js --name nameofyourapplication

POINT YOUR DOMAIN TO THE STRAPI SERVER USING NGINX REVERSE PROXY

The Strapi server is deployed and accessible by entering the server ip address and port. However it will be really nice if we can access Strapi on the server via a domain. Fortunately this is quite simple to set up, using an nginx reverse proxy. However for this you will have to ensure that nginx is running on your server. There are ample tutorials on the internet on how to install ngnix on your server and get it running, please follow one of those till this is done.

Create A records on your domain

You can add A records to your domain from the control panel of your domain hosting service. Create two A records as follows:

Host name: Strapi
IP Address: Your server’s ip address
Ttl: Default or 1 hour

Create another A record for your domain as follows:

Host name: www.Strapi
IP Address: Your server’s ip address
Ttl: Default or 1 hour

What this does is that if anyone goes to strapi.yourdomain.com or to www.strapi.yourdomain.com it will direct the request to your server’s ip address that you have specified in the A records.

CREATE NGINX SERVER BLOCK AND REVERSE PROXY

Just to reiterate we are now working on the server via SSH and not on the local machine. Thus far anyone who hits strapi.yourdomain.com will be redirected to your server ip. When this happens we need your server to return the Strapi process that we are running on localhost:1337 on your server. The server we are running is nginx and we need to configure the nginx server block for your domain to do this. If you are unfamiliar with nginx server blocks you can read this.

cd /etc/nginx/sites-available

The below is the configuration of the NGINX server block. This may look complex but is really quite simple, however you will have to read up on configuring these if you want to know what it is doing. Be sure to enter your domain name in the places marked in italics.

If a server block already exists for your domain in the /etc/nginx/sites-available directory open it otherwise create the file:

sudo nano yourdomain.com

Offcourse you can use the text editor of your choice, in the above command I have used nano. Paste the following into the file. Be sure to update yourdomain.com in italics in the code below. Also I have chosen to make my subdomain strapi.yourdomain.com, however instead of strapi you could choose any subdomain, but it must corresspond with the subdomain we have set up in the A records in the previous section.

server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name strapi.yourdomain.com www.strapi.yourdomain.com;location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:1337;
proxy_read_timeout 90;
}
ssl_session_cache builtin:1000 shared:SSL:10m;
# Defining option to share SSL Connection with Passed Proxy
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Defining used protocol versions.
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
# Defining ciphers to use.
ssl_prefer_server_ciphers on;
# Enabling ciphers
access_log /var/log/nginx/access.log;
# Log Location. the Nginx User must have R/W permissions. Usually by ownership
}

The key line to undersand is

proxy_pass http://localhost:1337;

What this boiler plate is telling nginx is that if a user makes a request on strapi.yourdomain.com or www.strapi.yourdomain.com, then pass this onto localhost:1337 which is the host and port our Strapi application is running on and lo and behold, magic, our application appears to the user via the said domains. Its as simple as that.

Enable the server block:

sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/

Next, test to make sure that there are no syntax errors in any of your Nginx files:

sudo nginx -t

If no problems were found, restart Nginx to enable your changes:

sudo systemctl restart nginx

SETTING UP SSL CERTIFICATES WITH LETSENCRYPT FOR NGINX

These instructions are for Ubuntu, if you are working on another platform, I’m sure you can find corressponding instructions for your platform:

Download the Lets Encrypt Client:

On Ubuntu 16.04 do:

apt-get update
sudo apt-get install certbot
apt-get install python-certbot-nginx

On Ubuntu 18.04 and later do:

apt-get update
sudo apt-get install certbot
apt-get install python3-certbot-nginx

Generate the certificates by doing:

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Press enter or click to view image in full size
Lets Encrypt’s 2 options to redirect http to https

Lets Encrypt offers you an option to redirect all requests such as to http, to https automatically. I generally choose option 2.

You can set up a cron job to renew expiring certificates automactically by doing:

Open the crontab file with the command:

crontab -e

Add the line

0 12 * * * /usr/bin/certbot renew --quiet

Thats it, now if you go to strapi.yourdomain.com you should be able to access strapi from there:

Press enter or click to view image in full size
Strapi successfully deployed to strapi.yourdomain.com

CONCLUSION

Congratulations on deploying Strapi to your own server. I feel that this is much more powerful than doing a black box install to Heroku where you don’t know what is happening or how it happened. It is actually quite simple, but as you saw in this article it may not be straightforward because there are so many small steps involved and getting any one of them wrong will comprise the deployment.

If you have any questions, don’t understand something or are stuck somewhere please feel free to reach out to me Arjuna at brahmaforces@gmail.com. Happy coding!

--

--

Arjun Singh Kochhar
Arjun Singh Kochhar

Written by Arjun Singh Kochhar

I am Arjuna a coder, painter, singer, poet, writer and kung-fu fighter. I work in Full Stack Javascript, React, Graphql and the MERN stack.

Responses (2)