Using Strapi in Production with HTTPs

For those of you who might might be living under a rock, let me give you a little info on Strapi the nodejs based headless CMS.

Strapi is a framework that allows you to quickly spin up a front-end and database agnostic Rest / GraphQL API, that also ships with its own React based Admin Panel. The core code and many of the current plugins are open-source (you can visit the github here).

I’ve spent the past few months using it to build out a project for community of gamers to track a lot of the data we get from a video game, and during this time I have spent some time talking to the developers behind Strapi.

As many of you know, testing a project on your local machine and doing so in a staging or a production environment can introduce some unique problems. I will be going over how to use Strapi with HTTPs (secured by Let’s Encrypt) on a linux virtual private server.

EDIT June 1st, 2020:

This guide no longer applies to Strapi stable versions, you will want to review the actual Strapi documentation located here:

I currently have no plans to update this guide.

EDIT May 1st, 2019:

I have tweaked the Nginx configs a bit to solve an issue with SSL + Nginx proxying that can sometimes give you the “white screen of death”. Strapi has stated they are working on this issue but this is a temporary patch in the mean time.

You can also refer to this issue for more information and for other use-cases like Apache:

A few requirements for this project are as follows:

  • A VPS (I will be using Vultr in this case)
  • A domain name that you can add DNS entries to (I will be using one connected to Cloudflare)
  • A little linux command line experience
  • (Optional) A Strapi project already hosted somewhere like Github

Software we will be using:

  • Strapi (Of course!)
  • Ubuntu 18.04 LTS Server
  • Node 10 / NPM 6
  • Nginx
  • MariaDB (MySQL, note that you can easily swap out for MongoDB if you want)
  • Certbot (For our automated SSL Certificate)

As a first step we need to prepare our VPS and get Ubuntu installed, in the case of Vultr this is as easy as few clicks.

After you have created your Vultr account and head to your dashboard, lets create a new VPS.

On the instances tab, click the little plus symbol on the right side. From here you can select the location, type of server (OS), some features, a startup script (such as doing this whole process automatically), SSH keys, and of course the hostname.

Here are the details I will be using:

  • Hosted in LA, USA
  • Ubuntu 18.04 LTS
  • $20 USD/month ( 2 CPU cores, 4GB Memory, and 3TB of monthly bandwidth )
  • No additional features (Highly recommend the backup option)
  • My laptop’s SSH key (For easy SSH access)
  • And of course the hostname “strapi-prod”

Then all we need to do is hit Deploy Now!

You should see your new VPS being installed and deployed!

After your VPS has been successfully deployed and is ready for you to connect, you can click on the entry in your dashboard and grab your user (root), your IP, and your password (If you added your SSH key you won’t need this to connect!).

Lets get connected and start installing our required packages!

First step, lets SSH to our new VPS, open up a terminal (If your on windows I recommend Putty):

ssh root@yourip

After your connected we need to do some updates and we need to install some software, below are a few commands we need to run.

Ubuntu Updates:

# Lets update Ubuntu to make sure we have all the latest packages
# The following will grab updates and install them
apt update && apt upgrade -y && apt dist-upgrade -y

Installing Node:

# Adding the Node 10 Repo 
# Since Ubuntu 18.04 ships with Node 8
curl -sL | sudo -E bash -# After this completes we need to actually install nodeapt install -y nodejs build-essential# You can confirm the installed versions using the followingnode --version && npm --version# In my case:
# Node - v10.11.0
# NPM - v6.4.1

Installing MariaDB + Nginx:

Thankfully Ubuntu 18.04 includes these two in the base repos so we just need to run the command to install them:

apt install -y mariadb-server mariadb-client nginx# After the install you can confirm the two are running:systemctl status mysql systemctl status nginx

Installing Certbot for our Let’s Encrypt SSL certificate:

apt install -y certbot python-certbot-nginx

(We will be using this later when we config nginx)

Setup our DNS:

This will change based on your host, a quick google with “configure dns on *myhost* “. A popular example would be GoDaddy or Google Domains. In my case I use Google Domains but have my name servers set to Cloudflare.

I recommend you create a sub-domain such as and set the A Record to your Vultr IP Address such as here in my example:

Note that sometimes this can take some time based on your host to be publicly available, can usually take between 5 minutes to 24 hours. With Cloudflare this will happen almost instantly. You can check the status of your DNS entry using the following website:

Not even 2 minutes after I created this entry:

Finally installing Strapi and/or cloning your Strapi project:

In our case here, we will be building a Strapi project right on this server, you will be able to skip the bulk of the following steps below here and skip straight to the Nginx config if you will be cloning your project.

Installing the latest Strapi version:

npm i -g strapi@alpha && strapi version

Create your MySQL database:

In order to create a new Strapi project (or cloning and using an existing one) we need to create the database and the user for Strapi to connect to.

# First we need to enter the MySQL shell, if you were not asked for
# a password when you installed MariaDB then you can use the follow
# else you can a -p to the end and enter that password
mysql -u root# You should be propted with the "MariaDB [(none)]>" shell
# Lets create the DB
create database strapiexample;# Then create the usercreate user strapiexample@localhost identified by 'yoursecurepass';# And finally grant permissions to the DBgrant all privileges on strapiexample.* to strapiexample@localhost;# Then flush privileges and quit the MySQL Shellflush privileges;

And that’s all you need to setup your database!

By now you should have your VPS all setup and ready to get started, we will create a new Strapi project but you can always clone your current Strapi project and setup the database (and importing from your development DB)

strapi new strapiexample

We will use most of the default values and enter the values you used to create your database:

  • Database: MySQL
  • Database name: strapiexample
  • Host:
  • Port: 3306
  • Username: strapiexample
  • Password: yoursecurepass

Now from here I personally recommend you use PM2 to run your Strapi project as a service, but you could also use the built in screen command.

If you want to use PM2, just install it with npm:

npm i -g pm2

Then change into your Strapi directory and start it (we will start in development for now as we will want to create some models).

NODE_ENV=development pm2 start strapi --no-pmx --name="strapiexample" -- start

A foot note to PM2 you can use it to start/stop and view the logs. It will also log Strapi to a file! These logs files are usually found in ~/.pm2/logs but you can also run pm2 logs strapiexample to see them in the console.

At this moment you should be able to get to your Strapi project on the default port:

Go ahead and create your user and lets get into the admin panel:

Now from here you can create models and add information, in this case we are going to skip this and configure the proxy settings in Strapi before we configure Nginx:

After you hit save, your Strapi server will restart and that is all you need in Strapi!

Now lets go and configure Nginx, this will be a two step process as we need to configure Nginx to use normal HTTP so that certbot can query the server and issue an SSL certificate. After we have the first certificate then we can configure the SSL proxy settings. Note if you are familiar with DNS authentication you can use that instead as it is far easier, else if you already have a paid certificate you can skip this first step and just upload your certificate and configure Nginx.

There will be two files we need to create, by default Nginx config files are stored in /etc/nginx we will be creating an “upstream” file to create an alias for the proxy (you can actually cluster multiple Strapi servers for load balance!)

Lets create that file here: /etc/nginx/conf.d/upstream.conf :

# Strapi upstream server
upstream strapi {
server localhost:1337;

After you have the upstream, lets create the server config:

Create a file such as /etc/nginx/sites-available/

server {# Listen HTTP
listen 80;
# Define LE Location
location ~ ^/.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
# Else Redirect to HTTPS // API
# location / {
# return 301 https://$host$request_uri;
# }

Then you need to delete the current config and symlink this new one and test it:

# Delete the current symlink configrm /etc/nginx/sites-enabled/default# Create a symlink for your new configln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ Check to make sure there are no errors in the Nginx Configservice nginx configtest# If it passes with [OK] restart Nginxservice nginx restart

From here with our temporary config we need to setup our SSL certificate using certbot:

# Run the automated Certbot Nginx commandcertbot --nginx

You will be asked some questions about the TOS and sharing your email, in my case I declined to share my email and of course accepted the TOS.

It will then ask you what domain you want to configure, in our case we only have one so we will enter 1 as that is the ID of our website.

It will go through the challenge process automatically and verify it can reach the domain. If it fails, it is likely your DNS settings have not propagated through the internet yet, so try again in a few hours.

For the next step it is asking if you want to redirect all HTTP traffic to HTTPs, you can simply say no here or enter 1 as we will be configuring this ourselves.

As you can see we now have our free SSL cert that is valid for 3 months and is super easy to renew! Now we just need to finish configuring Nginx to proxy to Strapi.

Note that if you want to setup the cert to automatically renew you can create a quick cronjob to run certbot renew I personally recommend running this once a week or once a month, as the cert will only renew 2 weeks prior to its expire date.

Remember to take note of the location of your SSL certificate as we will need that location to finish our setup.

Lets go back and modify our Nginx config located at /etc/nginx/sites-available/

I will give you the full config, so you can delete what is already there and paste this then modify or just add on the extra server block.

map $http_x_forwarded_host $custom_forwarded_host {
default "$server_name";
strapi "strapi";
server {
# Listen HTTP
listen 80;
# Define Root Location
root /var/www/html;
# Define LE Location
location ~ ^/.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/html;
# Else Redirect to HTTPS // API
location / {
return 301 https://$host$request_uri;
server {
# Listen HTTPS
listen 443 ssl;
# Root Location
root /var/www/html;
# SSL Config
ssl_certificate /etc/letsencrypt/live/; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# Proxy Config
location / {
proxy_pass http://strapi;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $custom_forwarded_host;
proxy_set_header X-Forwarded-Server $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_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

After you have modified the config lets go ahead and test it again and if it passes then restart Nginx

service nginx configtestservice nginx restart

After it has restarted you should now see your Strapi project is running on HTTPs (and redirects HTTP users to HTTPs)

Now of course your Strapi application is still accessible on port 1337 so if you would like to stop that (and you should) you can use the built in firewall on linux called UFW (Uncomplicated Firewall) or use something like IPTables.

I won’t go in depth here as you should make sure you read a few guides on hardening your VPS’s security such as disabling password based SSH (use keys!) and properly setting up your firewall. Most of this is a little much for a simple Strapi guide.

If you haven’t already, Strapi does have a Slack server you can join ( I am DMehaffy on there, please feel free to ping me with questions in the #help channel).

Thanks and Good luck!

Derrick Mehaffy

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store