How to Install Strapi CMS on Rocky Linux 9
Strapi is an open-source, headless Content Management System (CMS), built with the JavaScript programming language. Like other headless CMS’, Strapi doesn’t come with a frontend out of the box. It uses an API for its frontend which allows you to build the website using popular frameworks like React and Next.js. Based on a plugin system, Strapi is a flexible CMS whose admin panel and API are extensible - and whose every part is customizable to match any use case. Strapi also has a built-in user system to manage in detail what the administrators and end users have access to.
In this tutorial, you will learn how to install the community version of Strapi CMS on a Rocky Linux 9 server along with Nginx as a reverse proxy server.
Prerequisites
-
A server running Rocky Linux 9 with a minimum of 2GB RAM and 1 CPU Core.
-
A non-root user with sudo privileges.
-
A fully qualified domain name (FQDN) like
strapi.example.com
. -
Make sure everything is updated.
$ sudo dnf update
-
Few packages that your system needs.
$ sudo dnf install wget curl nano unzip yum-utils -y
Some of these packages may already be installed on your system.
Step 1 - Configure Firewall
The first step is to configure the firewall. Rocky Linux uses Firewalld Firewall. Check the firewall's status.
$ sudo firewall-cmd --state running
The firewall works with different zones, and the public zone is the default one that we will use. List all the services and ports active on the firewall.
$ sudo firewall-cmd --permanent --list-services
It should show the following output.
cockpit dhcpv6-client ssh
Strapi needs HTTP and HTTPS ports to function. Open them.
$ sudo firewall-cmd --permanent --add-service=http $ sudo firewall-cmd --permanent --add-service=https
Reload the firewall to apply the changes.
$ sudo firewall-cmd --reload
List all the services again.
$ sudo firewall-cmd --permanent --list-services
You should get the following output.
cockpit dhcpv6-client http https ssh
Step 2 - Install and Configure PostgreSQL
Strapi works with PostgreSQL 11 and above. Rocky Linux 9 ships with PostgreSQL 13 by default. We will use PostgreSQL 15 for our tutorial.
Run the following command to add the PostgreSQL GPG key.
$ curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /usr/share/keyrings/postgresql-key.gpg >/dev/null
Install the PostgreSQL repository RPM file.
$ sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
Disable the built-in PostgreSQL module.
$ sudo dnf -qy module disable postgresql
Now, you can install PostgreSQL using the command below.
$ sudo dnf install -y postgresql15-server
Initialize the database.
$ sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
Enable the PostgreSQL service.
$ sudo systemctl enable postgresql-15
Start the PostgreSQL service.
$ sudo systemctl start postgresql-15
Check the status of the PostgreSQL service.
$ sudo systemctl status postgresql-15 ? postgresql-15.service - PostgreSQL 15 database server Loaded: loaded (/usr/lib/systemd/system/postgresql-15.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2023-02-01 13:21:27 UTC; 41min ago Docs: https://www.postgresql.org/docs/15/static/ Process: 53088 ExecStartPre=/usr/pgsql-15/bin/postgresql-15-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS) Main PID: 53093 (postmaster) Tasks: 7 (limit: 5727) Memory: 45.7M CPU: 1.112s CGroup: /system.slice/postgresql-15.service ??53093 /usr/pgsql-15/bin/postmaster -D /var/lib/pgsql/15/data/ ??53094 "postgres: logger " ??53095 "postgres: checkpointer " ??53096 "postgres: background writer " ??53098 "postgres: walwriter " ??53099 "postgres: autovacuum launcher " ??53100 "postgres: logical replication launcher "
Launch the PostgreSQL shell.
$ sudo -i -u postgres psql
Create the Strapi database.
postgres=# CREATE DATABASE strapidb;
Create the Strapi user and choose a strong password.
postgres-# CREATE USER strapiuser WITH PASSWORD 'Your_Password';
Change the database owner to the Strapi user.
postgres-# ALTER DATABASE strapidb OWNER TO strapiuser;
Exit the shell.
postgres-# \q
Verify that your credentials work.
$ psql --username strapiuser --password --host localhost strapidb Password: psql (15.1) Type "help" for help. strapidb=>
Exit the shell by typing \q
.
Step 3 - Install Node.js
Rocky Linux 9 ships with Node v16 which is outdated. We will install the latest LTS version of Node which is v18 at the time of writing this tutorial.
Grab the Node v18 installer from Nodesource.
$ curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
Install Node.js.
$ sudo dnf install nodejs -y
Verify the Node.js version.
$ node -v v18.13.0
Step 4 - Install Strapi
Run the following command to install Strapi.
$ npx create-strapi-app@latest howtoforge-project Need to install the following packages: [email protected] Ok to proceed? (y) y
Enter y
to proceed with the installation. Next, you will be asked to choose the Installation type. Choose Custom to proceed and answer the questions as follows.
? Choose your installation type Custom (manual settings) ? Choose your preferred language JavaScript ? Choose your default database client postgres ? Database name: strapidb ? Host: 127.0.0.1 ? Port: 5432 ? Username: strapiuser ? Password: Your_Password ? Enable SSL connection: No
Depending on your requirements, you can either choose Typescript or JavaScript as the language for Strapi.
Once the installation is complete, you are ready to build your Strapi project.
Switch to the project directory.
$ cd howtoforge-project
Run the following command to build the project, including the Strapi Admin UI.
$ NODE_ENV=production npm run build
Start the Strapi server using the following command.
$ node ~/howtoforge-project/node_modules/.bin/strapi start
Your application should be visible on the URL http://<yourserverIP>:1337
. But first, open the port in the firewall.
$ sudo firewall-cmd --permanent --add-port=1337/tcp $ sudo firewall-cmd --reload
Once you open the URL, you should get the following screen.
Press Ctrl + C in the terminal to stop the server. You should delete the firewall rule because we won't need it.
$ sudo firewall-cmd --permanent --remove-port=1337/tcp $ sudo firewall-cmd --reload
Step 5 - Install and Configure PM2
Instead of starting the server manually, we can use PM2 (Process Manager 2) to manage the process and create a systemd service for the same.
Switch to the home directory.
$ cd ~
Install PM2.
$ sudo npm install pm2@latest -g
Create and open the PM2 configuration file for editing.
$ sudo nano ecosystem.config.js
Paste the following content in the file. Make sure to enter the correct directory name along with Postgres credentials.
module.exports = { apps: [ { name: 'strapi', cwd: '/home/navjot/howtoforge-project', script: 'npm', args: 'start', env: { NODE_ENV: 'production', DATABASE_HOST: 'localhost', DATABASE_PORT: '5432', DATABASE_NAME: 'strapidb', DATABASE_USERNAME: 'strapiuser', DATABASE_PASSWORD: 'Your_Password', }, }, ], };
Save the file by pressing Ctrl + X and entering Y when prompted once finished.
Run your Strapi instance in the background using PM2.
$ pm2 start ecosystem.config.js
You will get the following output.
------------- __/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____ _\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___ _\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__ _\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___ _\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____ _\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________ _\/\\\_____________\/\\\_____________\/\\\___/\\\/___________ _\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_ _\///______________\///______________\///__\///////////////__ Runtime Edition PM2 is a Production Process Manager for Node.js applications with a built-in Load Balancer. Start and Daemonize any application: $ pm2 start app.js Load Balance 4 instances of api.js: $ pm2 start api.js -i 4 Monitor in production: $ pm2 monitor Make pm2 auto-boot at server restart: $ pm2 startup To go further checkout: http://pm2.io/ ------------- [PM2] Spawning PM2 daemon with pm2_home=/home/navjot/.pm2 [PM2] PM2 Successfully daemonized [PM2][WARN] Applications strapi not running, starting... [PM2] App [strapi] launched (1 instances) ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? id ? name ? namespace ? version ? mode ? pid ? uptime ? ? ? status ? cpu ? mem ? user ? watching ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? 0 ? strapi ? default ? N/A ? fork ? N/A ? 0s ? 0 ? online ? 0% ? 0b ? navjot ? disabled ? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Applications running under PM2 restart automatically if they crash or get killed.
Create a startup systemd script using the following command.
$ pm2 startup
You will get the following output.
[PM2] Init System found: systemd [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u navjot --hp /home/navjot
Copy the command from the above output and run it.
$ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u navjot --hp /home/navjot
You will get the following output.
------------- __/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____ _\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___ _\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__ _\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___ _\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____ _\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________ _\/\\\_____________\/\\\_____________\/\\\___/\\\/___________ _\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_ _\///______________\///______________\///__\///////////////__ Runtime Edition PM2 is a Production Process Manager for Node.js applications with a built-in Load Balancer. Start and Daemonize any application: $ pm2 start app.js Load Balance 4 instances of api.js: $ pm2 start api.js -i 4 Monitor in production: $ pm2 monitor Make pm2 auto-boot at server restart: $ pm2 startup To go further checkout: http://pm2.io/ ------------- [PM2] Init System found: systemd Platform systemd Template [Unit] Description=PM2 process manager Documentation=https://pm2.keymetrics.io/ After=network.target [Service] Type=forking User=navjot LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity Environment=PATH=/home/navjot/.local/bin:/home/navjot/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin Environment=PM2_HOME=/home/navjot/.pm2 PIDFile=/home/navjot/.pm2/pm2.pid Restart=on-failure ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill [Install] WantedBy=multi-user.target Target path /etc/systemd/system/pm2-navjot.service Command list [ 'systemctl enable pm2-navjot' ] [PM2] Writing init configuration in /etc/systemd/system/pm2-navjot.service [PM2] Making script booting at startup... [PM2] [-] Executing: systemctl enable pm2-navjot... Created symlink /etc/systemd/system/multi-user.target.wants/pm2-navjot.service → /etc/systemd/system/pm2-navjot.service. [PM2] [v] Command successfully executed. +---------------------------------------+ [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd
Save the PM2 process list.
$ pm2 save [PM2] Saving current process list... [PM2] Successfully saved in /home/navjot/.pm2/dump.pm2
Your Strapi service is now running in the background in production mode.
Step 6 - Install Nginx
Rocky Linux 9 ships with an older version of Nginx. You need to download the official Nginx repository to install the latest version.
Create and open the /etc/yum.repos.d/nginx.repo
file for creating the official Nginx repository.
$ sudo nano /etc/yum.repos.d/nginx.repo
Paste the following code in it.
[nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true
Save the file by pressing Ctrl + X and entering Y when prompted.
Install the Nginx server.
$ sudo dnf install -y nginx
Verify the installation.
$ nginx -v nginx version: nginx/1.22.1
Enable and start the Nginx server.
$ sudo systemctl enable nginx --now
Check the status of the server.
$ sudo systemctl status nginx ? nginx.service - nginx - high performance web server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2023-02-01 15:01:29 UTC; 7s ago Docs: http://nginx.org/en/docs/ Process: 4637 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS) Main PID: 4638 (nginx) Tasks: 2 (limit: 10884) Memory: 1.9M CPU: 8ms CGroup: /system.slice/nginx.service ??4638 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf" ??4639 "nginx: worker process"
Step 7 - Install SSL
We need to install Certbot to generate the SSL certificate.
We will use the Snapd package installer for that. Since Rocky Linux doesn't ship with it, install the Snapd installer. It requires the EPEL repository to work.
$ sudo dnf install -y epel-release
Install Snapd.
$ sudo dnf install -y snapd
Enable and Start the Snap service.
$ sudo systemctl enable snapd --now
Install the Snap core package, and ensure that your version of Snapd is up to date.
$ sudo snap install core && sudo snap refresh core
Create necessary links for Snapd to work.
$ sudo ln -s /var/lib/snapd/snap /snap $ echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' | sudo tee -a /etc/profile.d/snapd.sh
Issue the following command to install Certbot.
$ sudo snap install --classic certbot
Use the following command to ensure that the Certbot command can be run by creating a symbolic link to the /usr/bin
directory.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Verify the installation.
$ certbot --version certbot 2.2.0
Run the following command to generate an SSL Certificate.
$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d strapi.example.com
The above command will download a certificate to the /etc/letsencrypt/live/strapi.example.com
directory on your server.
Generate a Diffie-Hellman group certificate.
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
To check whether the SSL renewal is working fine, do a dry run of the process.
$ sudo certbot renew --dry-run
If you see no errors, you are all set. Your certificate will renew automatically.
Step 8 - Configure Nginx
Open the file /etc/nginx/nginx.conf
for editing.
$ sudo nano /etc/nginx/nginx.conf
Add the following line before the line include /etc/nginx/conf.d/*.conf;
.
server_names_hash_bucket_size 64;
Save the file by pressing Ctrl + X and entering Y when prompted.
Create and open the file /etc/nginx/conf.d/strapi.conf
for editing.
$ sudo nano /etc/nginx/conf.d/strapi.conf
Paste the following code in it.
server { # Redirect any http requests to https listen 80; listen [::]:80; server_name strapi.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name strapi.example.com; access_log /var/log/nginx/strapi.access.log; error_log /var/log/nginx/strapi.error.log; # TLS configuration ssl_certificate /etc/letsencrypt/live/strapi.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/strapi.example.com/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/strapi.example.com/chain.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; # OCSP Stapling --- # fetch OCSP records from URL in ssl_certificate and cache them ssl_stapling on; ssl_stapling_verify on; ssl_dhparam /etc/ssl/certs/dhparam.pem; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:1337; } }
Save the file by pressing Ctrl + X and entering Y when prompted once finished.
Verify the Nginx configuration file syntax.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Restart the Nginx service.
$ sudo systemctl restart nginx
You can now access Strapi CMS via the URL https://strapi.example.com
. You will see the following page which shows that Strapi is running in production mode.
Visit the https://strapi.example.com/admin
URL to create an administrator user.
Fill in your admin details and click the Let's start button to proceed to the administrator dashboard screen.
From here on, you can start creating content on Strapi.
Step 9 - Upgrade Strapi
The first step in upgrading Strapi is to stop the server.
$ cd ~ $ pm2 stop ecosystem.config.js
Switch to the project directory and open the package.json
file for editing.
$ cd howtoforge-project $ nano package.json
Upgrade all of the Strapi package version numbers to the latest stable Strapi version. You can get the latest available version from Strapi's GitHub releases page.
"devDependencies": {}, "dependencies": { "@strapi/strapi": "4.5.5", "@strapi/plugin-users-permissions": "4.5.5", "@strapi/plugin-i18n": "4.5.5", "pg": "8.6.0" },
Here you need to change 4.5.5
to the latest stable version. Save the file by pressing Ctrl + X and entering Y when prompted once finished.
Install the upgraded version.
$ npm install
Rebuild the Administration panel.
$ NODE_ENV=production npm run build
Start the server again.
$ cd ~ $ pm2 start ecosystem.config.js
Your Strapi installation is now upgraded and running.
Conclusion
This concludes our tutorial on installing Strapi CMS on a Rocky Linux 9 server along with Nginx as a reverse proxy server. If you have any questions, post them in the comments below.