Skip to main content

GUI - Strapi deployment by hand

Objective

To show an efficient way for a Strapi project deployment by hand.

Content

Introduction

These steps are based on the Strapi's and Digital Ocean's documentation for deploying a Strapi project by hand in a Droplet, so we are also assuming that you have installed an Ubuntu Linux server that is in its 18.04 version at least. It is also important to mention that for the last modification of this file, we are using Strapi v4.

We hope that you find this guide helpful, as we are trying to centralize all de documentation into a single file, and we are also providing some other findings that have helped to solve several issues for Strapi application deployment by hand.

Configure the basics in your droplet, hosting, ec2, whatever tool you're using

Windows OS

If you are using a Windows Operative system, we recommend you to install OpenSSH services to use from PowerShell

  • Go to your service provider panel, create an ssh access door and access it from your computer by using ssh [username]@[ip-address] and your password/ssh key
  • Create a non-root user, and log into it:
GUI - Create Debian user

GUI - Create Debian user

Objective

Describe a standarized way to create Linux Debian users.

Content

Introduction

For several reasons it is recommended to create an admin user different to the root user, that's why we are going to show the steps required to do so, remmember that these steps are intended for Debian based Linux distrubutions.

Prerequisites

You need to be logged into the server with your root user with superuser privileges and have access to the command line.

Create new user

You need to choose a new username + password for the user creation, we recommend storing this information, so you don't forget about it

# Create the non-root user
adduser username
# After executing the previous command you will be asked
# for some information, rememb you will need to keep track
# of username and password, write them down...

# Give sudo privileges to the non-root user
usermod -aG sudo username

Access to the new user

You have 2 options to access your newly created user:

  • If you are still on your command line with your root user, you can use
sudo su username
  • If you need to connect again to your server, now you can use your new account keys (username and password)
ssh [username]@[ip-address]

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramirez Herrera12/12/2023
  • Add some protection rules with basic firewall configuration
# Allow SSH secure communication
sudo ufw allow OpenSSH
# Make the previous rule take effect
sudo ufw enable
# Make sure OpenSSH is listed and Allowed
sudo ufw status
  • Install nodejs and make sure it has execution privileges for all your users
GUI - Install NodeJS in Debian

GUI - Install NodeJS in Debian

Objective

Describe a standarized way to install NodeJS uder a Debian Linux distribution environment.

Content

Introduction

Serveral times you are going to need to use NodeJS for your application to work, but most of the OS won't have NodeJS installed by default, so you need to make sure to install it correctly.

Prerequisites

You need to be logged into the server with a user that has superuser privileges and have access to the command line.

Install NodeJS

If you just want the latest release for NodeJS to be installed, just execute these commands:

sudo apt update # Grant you are using most recent packages
sudo apt install nodejs # Install the latest/stable release
sudo apt install npm # Make sure npm gets installed
node --version # Check your NodeJS version
npm --version # Check your npm version

Different version from the latest

Sometimes the app development requires for a specific NodeJS version to be installed, then, you need to execute these comands:

# If you need any other node version...
sudo npm cache clean -f # Force to clean any npm cache
sudo npm install -g n # Install node helper
sudo n [version] # sudo n 18.15.0 as example
node --version # Check your node version

Give execution privileges to all users

You now have NodeJS installed, but it might only work with your current user, you can give privileges to all users by executing:

cd ~ # Go to root folder
mkdir ~/.npm-global # Create node global directory
npm config set prefix '~/.npm-global' # Global node_modules will be installed here
sudo nano ~/.profile # Create or modify profile file
--------------------
# Add these lines
# set PATH so global node modules install without permission issues
export PATH=~/.npm-global/bin:$PATH
--------------------
source ~/.profile # Use previous file as system variables

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramirez Herrera12/12/2023
  • Make sure you have git installed, otherwise, install it by using sudo apt install git

Database creation

DBMS

As several users recommend using PosgreSQL, we are going to stick to that configuration, if you ever need to use any other Database Management System, we encorage you to find the right documentation, test it and add your learnings to the wiki and link it to this document

We are going to install PostgreSQL, modify the default user's password and create a database, don't forget to keep the database port, database name, user name and user's password

# Grant you are using most recent packages
sudo apt update
# Install postgresql packages
sudo apt install postgresql postgresql-contrib

# Start postgresql service
sudo systemctl start postgresql.service

# Log into postgres user (it was created along postgres installation)
sudo -i -u postgres

# Execute postgresql
psql

# Change postgres user password
postgres=# ALTER USER postgres PASSWORD 'new password';

# Create the database
postgres=# createdb dbName

Local/server repo configurations

Misconfigurations

Make sure you read everything here carefully, as some misconfigurations may result in several hours spent making fixes.

  • Create the next folder structure inside the config folder of your Strapi application: config/env/production

  • Inside production create a file named database.js, copy and paste the next snippet:

./config/env/production/database.js
const { parse } = require('pg-connection-string');

module.exports = ({ env }) => {
const { host, port, database, user, password } = parse(env('DATABASE_URL'));

return {
connection: {
client: 'postgres',
connection: {
host,
port,
database,
user,
password,
ssl: { rejectUnauthorized: false },
},
debug: false,
},
};
};
  • Make sure you commit and push your changes to the repo

  • Make sure you are loged into your server with the non-root user, navigate to /var/www and clone your repo by giving it your domain name as the name of the folder

# Move to folder
cd /var/www
# clone your repository
git clone [repo-url] [your-domain-name]
Use your domain

It is very important you clone your repo with your domain name as the name of the folder, as it will help you a lot for the following configurations

  • Move to your repo folder, install node dependencies and install node's posgresql dependencies too.
# Move to folder
cd [your-domain-name]
# Install project dependencies
npm install
# Make sure you have installed posgresql dependencies
npm install pg --save
  • Create .env file and add the required variables
# Create and open .env file
sudo nano .env

# Make sure your file has the next variables
------------
DATABASE_PORT=value
DATABASE_NAME=value
DATABASE_USERNAME=value
DATABASE_PASSWORD=value
HOST=value
PORT=value
APP_KEYS=value
API_TOKEN_SALT=value
ADMIN_JWT_SECRET=value
JWT_SECRET=value
DATABASE_URL=value
# If you are sure that you will always run this on production mode, you can add NODE_ENV=production
------------

# This file will only be used for the "npm run build" command
  • Build the project with sudo NODE_ENV=production node run build

Run your project with PM2

GUI - Install and configure PM2

GUI - Install and configure PM2

Objective

To show an efficient way to install and configure PM2 to run an application.

Content

Prerequisites

You need to have NodeJS and npm installed in the target system. If you have any doubt, please refer to install NodeJS in Debian.

Installing PM2

You need to make sure you are in the root folder by executing cd ~. Then, install pm2 globally with npm install pm2@latest -g.

If the previous npm install didn't work, you can try to execute:

apt update 
apt install sudo curl
curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh
sudo -E bash -

Updating PM2

Make sure PM2 is already installed, you can check that by executing: pm2 --version.

Then, just execute pm2 update.

Configuring PM2

First, we make sure we centralize configuration files under a common folder, for that, we execute:

# Navigate to your home directory
cd ~
# Create a new directory for your configuration files called NodeWebhooks
mkdir ~/NodeWebhooks
# Then navigate to the new directory
cd ~/NodeWebhooks
  • Initialize PM2, this will create a default configuration file, you need to edit that file:
# Create default ecosystem.config.js file
pm2 init
# Modify the created file
sudo nano ecosystem.config.js
  • Replace the file content with the next lines of code, make sure you place your own values:
ecosystem.config.js
module.exports = {
apps: [
{
name: '[app-or-service-name]',
// Path to the working app directory, you can replace it entirely
cwd: '/var/www/[your-domain-name]',
// You can use your own package manager like npm
script: 'yarn',
args: 'start',
env: {
HOST: '[your-domain-name]',
PORT: '[your-application-port]',
NODE_ENV: 'production',
DATABASE_HOST: 'localhost',
DATABASE_PORT: '5432',
DATABASE_NAME: 'dbName',
DATABASE_USERNAME: 'postgres',
DATABASE_PASSWORD: 'postgres_user_password',
DATABASE_URL: 'postgresql://[databas-username]:[database-password]@[database-host]:[database-port]/[database-name]',
},
},
],
};
Use your values

Remember you need to modify previous values with yours. All the env variables are just examples, if you don't need any environment variables, just delete them.

Execute your project

  • Execute the project by writing pm2 start ecosystem.config.js

  • Save your PM2 configurations for whenever server needs a reboot

# Generate the startup command
pm2 startup systemd

# Copy and paste the command provided by the previous execution

pm2 save # save the current pm2 configuration and state
  • Make sure you have no errors by checking the execution of pm2 logs command, the service should be up and running

Multiple apps with the same configuration file

If you ever require to run multiple applications at the same time with PM2, you can do that by adding other entries to the apps array of the ecosystem.config.js file that was created under NodeWebhooks when you executed pm2 init.

Debuging PM2

If you ever have the need to debug the PM2 process run, you should first execute pm2 list and this will give you the list of the different processes running with PM2 and note the id of your process.

With your process id execute pm2 info [id] or pm2 describe [id] and this will give you enough information to start your debugging, you can also check your configuration file to check if any information is wrong or also, execute pm2 monitor [id].

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramírez Herrera26/12/2023
Check your configuration

Make sure you have no errors by checking the execution of pm2 logs command, the service should be up and running

Configure Nginx server

Make sure your folder under /var/www path has the right permissions

# Assign ownership to current user
sudho chown -R $USER:$USER /var/www/[your-domain-name]
# Change folder permissions
sudo chmod -R 755 /var/www/[your-domain-name]

Follow the Nginx guide to create the configuration file and paste the next template, we will modify the template later:

/etc/nginx/sites-available/[your-domain-name]
server {
# Use your own application port
listen 80;
listen [::]:80;

server_name [your-domain-name];

# You can replace the whole direction to match yours
root /var/www/[your-domain-name];
index index.html index.htm index.nginx-debian.html;

location / {
try_files $uri $uri/ =404;
}
}
GUI - Install and configure Nginx

GUI - Install and configure Nginx

Objective

To show an efficient way to install and configure Nginx to serve an application.

Content

Introduction

To first install Nginx can be a headache, every single project might have specific configuration needs, maybe you want to redirect from a url to another one, maybe you have a SPA (Single-page application) or maybe you want to modify a file that has SSL applied.

Prerequisites

You need to be logged into the server with a user that has superuser privileges and have access to the command line.

Installing Nginx

We recommend to make sure you have the latest packages by executing

sudo apt update

Make sure you are in the root folder by executing cd ~. Then, install Nginx with

sudo apt install nginx

Verify the installation by executing

nginx -v

Allow Nginx in firewall

Your server might be blocking all TCP communication by default, so we need to allow Nginx to handle this communication. You migh have already installed ufw, but if not, you need to install it by executing sudo apt-get install ufw.

Adjust firewall to allow http and https, in other words, allow Nginx Full

# Verify the applications that ufw is aware of
sudo ufw app list
# Allow http and https
sudo ufw allow 'Nginx Full'
# Apply previous changes
sudo ufw enable
# Check that OpenSSH and Nginx Full are allowed
sudo ufw status

Check everything is ok

Make sure nginx is up and running by executing next commands:

# The active status shoud be active and running
sudo systemctl status nginx

# This will show some IP addresses
ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'
Test on your browser

If you copy the resulting IP address and paste it into your browser, you should see an nginx message

Creating the configuration file and enabling it

By default, Nginx will create a folder under /etc/nginx when installed, all configuration files will be written in the sites-available folder contained in the previously mentioned nginx folder. Every configuration file should be named after the domain name it will represent.

Move to /etc/nginx/sites-available and create the configuration file with:

# Move to sites-available folder
cd /etc/nginx/sites-available
# Create the configuration file, it doesn't need any file extension
touch ./[your-domain-name]

Create a symbolic link to enable the previous config file

sudo ln -s /etc/nginx/sites-available/[your-domain-name] /etc/nginx/sites-enabled/

Understanding basic Nginx configurations

Directives

Nginx is conformed by directives, where you can have simple directives (ending with a semicolon ;) and block directives (surronded by braces { }). A block directive can contain simple directives and other block directives. If a block directive can have other directives inside braces, it is called a context (examples: events, http, server, and location). Directives placed in the configuration file outside of any contexts are considered to be in the main context. The events and http directives can reside in the main context, server in http, and location in server.

To have a better understanding of the previous explanation, look the next configuration:

# Http belongs to main context (the config file is the main context)
http {
# Server belongs to http context, as it is inside http
server {
# Location belongs to server context, as it is inside server
location / {
root /var/www;
}
location /images/ {
root /data;
}
}
}

The location directive compares the given parameter (in this case /) against the current URI from the request and if there is a matching request, the URI will be added to the path specified in the root directive (in this case, to /var/www). If there are several matching location blocks Nginx selects the one with the longest prefix match. In the previous example, if you go to /images/ it will match / and /images/, as /images/ has the longest prefix match, it will be used.

Processing requests

Knowing the previous, we need to understand how Nginx processes the requests. Nginx first decides which server should process the request by comparing the host provided under the server_name directive, every server block is treated as a virtual server and if no server_name is provided, Nginx uses the empty name "" as the server name, allowing this server to process requests without the Host header field. Then it looks to the listen directive that sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests.

With all the previous, we can expand our example, we are going to remove the http block and let only the server block.

server {
# Listen to port 8080
listen 8080;
# Catch all IPv6 addresses that listen to port 8080
listen [::]:8080;
# Sets the Host/s to catch the requests from, first name becomes the primary server name
server_name example.com www.example.com;

location / {
root /var/www;
}
location /images/ {
root /data;
}
}

Setting a proxy server

There are several times where the intended usage for a specific location is to pass the requests to another server and retrieve the response from it. Imagine you have an aplication under www.myapplication.com and every request serves an HTML page, but whenever you receive some request to www.myapplication.com/api/ you want it to send the request to your backend server that you already have configured, then you need a proxy server like this:

server {
listen 80;
listen [::]80;

server_name www.myapplication.com;

location / {
root /var/www;
}
location /api/ {
proxy_pass www.myapplicationbackend.com:8080;
}
}

If a keepalive connection is required (for constant frontend to backend communication for example) then you need to set proxy_http_version 1.1; directive. You can also set some headers by adding a proxy_set_header directive, for example proxy_set_header Host $host; or proxy_set_header Connection '';.

Giving specific files to serve

In the previous configuration documents we've used location with the root directive, that will try to 'build' the given request with the given root path, for example if you have:

location /home/ {
root /assets/images;
}

A request to /home/front.png will be resolved into /assets/images/home/front.png.

But you might want to specify the files to deliver if a specific location has been reached, like when you have a SPA (Single-page application) and to do so you need to use the try_files directive that checks the existence of files in the specified order and uses the first found file for request processing.

server {
listen 80;
server_name someserver.com;
root /var/www;

location / {
# This will try to find the given uri as a file name, if not found, it will render the index.html specified in the root directive of the previous context
try_files $uri /index.html;
}
}

Variables and further reading

As you've seen on some of the previous examples, we are using variables like $uri or $host, these variables are embeded variable names and can be used anywhere in the configuration files.

We know that these are only the basics to make Nginx configuratio and there are a lot of features and variables to check and understand from this tool, so if you ever need more in-depth of Nginx functionalities, we recommend you to go to the official documentation.

Set current configurations to start working

If you read Nginx documentation you will see that they tell you to use nginx -t and nginx -s reload commands to load new configurations, but if this does not work, then:

# Test configuration files are correct
nginx -t

# Restart nginx so it takes the changes
sudo service nginx restart
# But you can also use...
sudo systemctl restart nginx

# Check nginx status by writing:
sudo systemctl status nginx

Debugging

The first thing you should check is that you have nginx installed with nginx -v, then execute nginx -t to test your configuration files, if all files are correct, check that your files are under the sites-available folder and linked to the sites-enabled under the symbolic link. You can also check the system status for nginx with sudo systemctl status nginx. The final recommendation goes for the server configurations, where you can set the server logs file location:

server {
# Set where the logs will be placed
access_log /var/log/nginx/nginx.acess.log;
error_log /var/log/nginx/nginx.error.log;
}
More tips and tricks

If you have any other tips or tricks with Nignx, please add them to this guide.

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramirez Herrera03/01/2023
Test your configurations

Make sure you've tested your config files and restarted the nginx service.

Add SSL certificate

Follow the SSL certificate installation over Nginx guide.

GUI - Add SSL to Nginx server

GUI - Add SSL to Nginx server

Objective

To show a standarized way to install and configure an SSL certificate with autorenewal to Nginx servers by using Certbot.

Content

Introduction

Prerequisites

You need to be logged into the server with your root user with superuser privileges and have access to the command line. You also need to already have an Nginx configuration up and running and python3 installed in your hosting service.

Install dependencies

We are going to install certbot and a Python3 helper that will help us to install SSL certificates over Nginx.

sudo apt install certbot python3-certbot-nginx 

Add certificate

There are two ways to add a certificate, the first one is to execute a commmand that will trigger some questions that we need to answer with:

sudo certbot -d [your-domain-name] -d [your-other-domain-or-subdomain]

The other one is giving the answer to this questions through flags.

sudo certbot --nginx --redirect --agree-tos --no-eff-email -m youremail@mail.com -d domain.com -d www.domain.com

Enable autorenewal

The certificate has a limited ammount of time of availability, so, if you don't want to be manually generating new SSL certificates, you need to activate the autorenewal with:

sudo certbot renew --dry-run

Check SSL installation

The previous commands will make modifications under your Nginx config files, so if you want to check that SSL has been successfully configurated, you can go to /etc/nginx/sites-available/[your-domain-name] and check its contents.

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramirez Herrera04/01/2023

Modify once more the Nginx config file by using sudo nano /etc/nginx/sites-available/[your-domain-name]. In the first 'server' entry you see, you will find some certbot related configs right under 'server_name' line and above 'listen [::]443 ssl...'. Paste the next code right between those lines and make sure everything else remains the same.

/etc/nginx/sites-available/[your-domain-name]
 location / {
proxy_pass http://[your-domain-name]:1337;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Host $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";
proxy_pass_request_headers on;
}
Rename values

Make sure that every 'server_name' and '$host' mention has your domain name as a value and that the root remains being '/var/www/[your-domain-name]'

Check that all the configurations are ok with sudo nginx -t and restart the nginx service with sudo systemctl restart nginx.

Furthermore

If you have followed all the previous steps and you still have some errors, please try to do it once again from the beginning, if you still have troubles, contact a teammate, and if both of you can't find a way to solve it, then you need to report this to the team.

Versions

VersionDescriptionResponsiblesDate
1.0Guide creationEmmanuel Antonio Ramírez Herrera26/04/2023