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.
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 -vStrapi 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 listSo 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.3Now 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)
\conninfoCreating 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:
\lIf you want to check whether your user was created you can list all of the user roles:
\duTo quit the postgres=# prompt do:
\qNote 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-projectThe 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.
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();
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 buildPush 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
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.
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
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.gitYou will get the url from your github repository.
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/mystrapiapplicationScp 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 -aThis 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 installStart 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 nameofyourapplicationTo see the status of your application do:
pm2 statusYou should get a status showing that your application is online as follows:
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.jsOnly 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:1337You should see a message stating that your 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 nameofyourapplicationAnd then simply running
npm run developon 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 nameofyourapplicationPOINT 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 hourCreate another A record for your domain as follows:
Host name: www.Strapi
IP Address: Your server’s ip address
Ttl: Default or 1 hourWhat 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-availableThe 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.comOffcourse 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 Proxyssl_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 ciphersaccess_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 -tIf no problems were found, restart Nginx to enable your changes:
sudo systemctl restart nginxSETTING 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-nginxOn Ubuntu 18.04 and later do:
apt-get update
sudo apt-get install certbot
apt-get install python3-certbot-nginxGenerate the certificates by doing:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.comLets 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 -eAdd the line
0 12 * * * /usr/bin/certbot renew --quietThats it, now if you go to strapi.yourdomain.com you should be able to access strapi from there:
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!