How to Install Backdrop CMS with LEMP on Rocky Linux 8

Install Backdrop CMS with LEMP Stack on Rocky Linux 8 using Nginx, MariaDB, PHP-FPM, SELinux, firewalld, and HTTPS on a fresh VPS.
A glowing database, CMS panel, and server node represent Backdrop CMS on Rocky Linux 8.

Install Backdrop CMS with LEMP Stack on Rocky Linux 8 by putting Nginx, MariaDB, and PHP-FPM behind SELinux and HTTPS. On a fresh VPS with DNS already pointed at the server, you can reach the Backdrop installer in about 10–15 minutes.

Prerequisites

  • Rocky Linux 8.x with at least 1 GB of RAM, 10 GB of free disk space, and a public IPv4 address.
  • Root access or a sudo-enabled user over SSH. The commands below assume a non-root user and use sudo.
  • A domain such as YOUR_DOMAIN with an A record pointing to the VPS. Certbot needs this name to resolve publicly before it can issue a certificate.
  • A strong, unique database password and a separate strong password for the Backdrop administrator.
  • A VPSLake Linux VPS running Rocky Linux 8 is suitable for a small Backdrop site.
  • Do not run Apache on ports 80 or 443 on this server; this guide installs Nginx as the web server.

Step 1: Install the LEMP packages

Rocky Linux 8 uses dnf, and the Remi PHP stream provides a current PHP release while retaining Rocky’s PHP-FPM service layout.

sudo dnf update -y
sudo dnf install -y epel-release firewalld mariadb-server unzip curl bind-utils policycoreutils-python-utils
sudo dnf module enable nginx:1.20 -y
sudo dnf install -y nginx
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-8.rpm
sudo dnf module reset php -y
sudo dnf module enable php:remi-8.3 -y
sudo dnf install -y php php-fpm php-cli php-mysqlnd php-gd php-mbstring php-opcache php-xml php-curl php-zip php-intl
sudo systemctl enable --now firewalld mariadb nginx php-fpm
php -v
nginx -v
mariadb --version

You should see PHP 8.3.x, an Nginx version, and a MariaDB client version. Patch numbers change as Rocky, Remi, and EPEL publish updates.

The package command also installs the tools used later for archive extraction, DNS checks, and SELinux policy management. Starting the services now makes it easier to identify a package or socket problem before Backdrop is added.

On Rocky Linux, PHP-FPM may initially run its pool as apache. Nginx needs to read the PHP-FPM socket, so assign the pool and socket to the nginx account before testing the site.

sudo sed -ri 's/^[; ]*user = .*/user = nginx/; s/^[; ]*group = .*/group = nginx/; s/^[; ]*listen.owner = .*/listen.owner = nginx/; s/^[; ]*listen.group = .*/listen.group = nginx/' /etc/php-fpm.d/www.conf
sudo systemctl restart php-fpm
sudo systemctl is-active php-fpm
active

Step 2: Create a MariaDB database and user

Backdrop keeps content, accounts, and configuration data in MariaDB, so give this site its own database and a local-only database account.

sudo mariadb <<'SQL'
CREATE DATABASE backdrop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'backdrop_user'@'localhost' IDENTIFIED BY 'YOUR_DATABASE_PASSWORD';
GRANT ALL PRIVILEGES ON backdrop.* TO 'backdrop_user'@'localhost';
FLUSH PRIVILEGES;
SQL
sudo mariadb -e "SHOW DATABASES LIKE 'backdrop';"

Replace YOUR_DATABASE_PASSWORD with a unique password before running the block. The check should return one row named backdrop; keep the database name, username, and password for the browser installer.

The account is restricted to localhost, so a remote host cannot use these credentials to connect to MariaDB. The utf8mb4 character set also gives Backdrop room for full Unicode content instead of relying on an older default encoding.

Step 3: Download Backdrop and prepare the document root

Using a numbered release archive avoids pulling an unstable development branch and makes future upgrades easier to identify. This guide uses Backdrop 1.35.1, the current release listed by the project.

BACKDROP_VERSION=1.35.1
sudo curl -fL -o /tmp/backdrop.zip "https://github.com/backdrop/backdrop/releases/download/${BACKDROP_VERSION}/backdrop.zip"
sudo mkdir -p /tmp/backdrop-release /var/www/backdrop
sudo unzip -q /tmp/backdrop.zip -d /tmp/backdrop-release
BACKDROP_ROOT="$(find /tmp/backdrop-release -type f -name index.php -printf '%h\n' | head -n 1)"
sudo cp -a "$BACKDROP_ROOT"/. /var/www/backdrop/
sudo mkdir -p /var/www/backdrop/files

The web server only needs to write uploads and generated files. Keep the application code owned by root, make it readable by Nginx, and leave settings.php temporarily group-writable so the installer can save the database connection.

This split is useful during upgrades: an attacker who gains a web process should not be able to rewrite the CMS core, while Backdrop can still create media and generated image styles under files.

sudo chown -R root:nginx /var/www/backdrop
sudo find /var/www/backdrop -type d -exec chmod 750 {} \;
sudo find /var/www/backdrop -type f -exec chmod 640 {} \;
sudo chown -R nginx:nginx /var/www/backdrop/files
sudo chmod -R 770 /var/www/backdrop/files
sudo chmod 660 /var/www/backdrop/settings.php

Apply SELinux labels that distinguish read-only application code from the writable upload directory. This leaves SELinux enforcing while allowing PHP-FPM to manage uploaded assets.

sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/backdrop(/.*)?'
sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/backdrop/files(/.*)?'
sudo restorecon -Rv /var/www/backdrop

Step 4: Configure Nginx for Backdrop

Backdrop uses a front controller for clean URLs, so Nginx must pass unknown paths to index.php while refusing direct access to the site settings and executable files in uploads.

Create /etc/nginx/conf.d/backdrop.conf with this content:

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

    root /var/www/backdrop;
    index index.php;
    client_max_body_size 32m;

    location / {
        try_files $uri @backdrop;
    }

    location @backdrop {
        rewrite ^/(.*)$ /index.php?q=$1 last;
    }

    location ^~ /files/styles/ {
        try_files $uri @backdrop;
    }

    location = /settings.php {
        deny all;
    }

    location ~ ^/files/.*\.php$ {
        deny all;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTP_PROXY "";
        fastcgi_pass unix:/run/php-fpm/www.sock;
    }
}

Replace YOUR_DOMAIN with the DNS name that points to this VPS. Test the syntax before reloading Nginx.

sudo nginx -t
sudo systemctl reload nginx
syntax is ok
test is successful

Step 5: Open the firewall and enable HTTPS

Keep SSH available for administration, allow HTTP for the initial certificate challenge, and allow HTTPS for the finished site.

sudo firewall-cmd --permanent --zone=public --add-service=ssh
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

The service list should include ssh, http, and https. Install Certbot and let it update the Nginx server block with a redirect from HTTP to HTTPS.

sudo dnf install -y certbot python3-certbot-nginx
sudo certbot --nginx --redirect --agree-tos --no-eff-email -m YOUR_EMAIL -d YOUR_DOMAIN

Replace YOUR_EMAIL with an address that can receive renewal notices. Certbot must resolve YOUR_DOMAIN to this VPS and reach port 80 from the public internet.

The Nginx plugin edits the active server block and installs the redirect, so do not replace the file with a second HTTPS block afterward. Keep the DNS name and certificate name identical to avoid a browser certificate warning.

Step 6: Run the Backdrop installer

The browser installer writes the site settings and creates the first administrator account without putting that password into shell history.

Open https://YOUR_DOMAIN/core/install.php in a browser. Select the standard installation profile if prompted, then enter these database values:

  • Database name: backdrop
  • Database username: backdrop_user
  • Database password: the value used for YOUR_DATABASE_PASSWORD
  • Database host: localhost

Enter a site name and create a unique administrator password. When the installation finishes, visit the home page and sign in over HTTPS. If the installer opens at the domain root instead, follow its normal setup flow; the direct path is useful when the home page has already been customized.

After the installer completes, remove write access from the settings file. Backdrop’s official installation instructions specifically recommend protecting this file after setup.

sudo chown root:nginx /var/www/backdrop/settings.php
sudo chmod 640 /var/www/backdrop/settings.php

Verify the Backdrop installation

These checks confirm that the services are running, Nginx accepts the configuration, PHP has the database and image modules, and the public site answers over TLS.

sudo systemctl is-active nginx php-fpm mariadb firewalld
sudo nginx -t
curl -fsSI https://YOUR_DOMAIN
sudo php -m | grep -E 'curl|gd|mbstring|mysqli|mysqlnd|PDO|xml|zip'
active
active
active
active
HTTP/2 200

The exact extension order can differ. A successful HTTPS response and a loaded PDO/MySQL driver show that Nginx can hand requests to PHP-FPM; the final proof is a working Backdrop dashboard and an upload test from the administration area. Backdrop’s system requirements describe the supported PHP, MariaDB, and Nginx requirements behind this setup.

Troubleshooting

502 Bad Gateway

Nginx cannot open the PHP-FPM socket, usually because PHP-FPM is stopped or its pool still uses the apache account. Run sudo systemctl status php-fpm, check that /run/php-fpm/www.sock exists, reapply the pool changes from Step 1, and restart PHP-FPM.

The installer reports missing PHP extensions

The active PHP module stream may not contain the required modules, or PHP-FPM may still have old workers. Run sudo dnf install -y php-mysqlnd php-gd php-mbstring php-xml php-curl php-zip php-intl, then run sudo systemctl restart php-fpm and refresh the installer.

Clean URLs return 404 while the front page works

The Backdrop named location is absent, the request is reaching a different Nginx server block, or the configuration was not reloaded. Check sudo nginx -T | grep -A6 -B3 'server_name YOUR_DOMAIN', confirm the @backdrop rewrite, then run sudo nginx -t && sudo systemctl reload nginx.

Certbot cannot validate the domain

The DNS record may point to another address, or port 80 may be blocked by the VPS control panel or an upstream firewall. Run dig +short YOUR_DOMAIN, compare the result with the VPS public IP, and allow HTTP before retrying Certbot.

Hardening and maintenance

  • Apply updates with sudo dnf update -y, and back up both the MariaDB database and /var/www/backdrop/files before changing the CMS.
  • Keep SELinux enforcing and do not make the entire webroot writable. Only files needs write access for normal uploads.
  • Test renewal with sudo certbot renew --dry-run after the certificate is active.
  • If Backdrop’s update manager needs outbound HTTPS and SELinux logs a denial, inspect that specific denial before enabling the narrowly relevant web-server network boolean.

FAQ

Can I install Backdrop without a domain?

You can test the application over the VPS IP address, but a domain is the practical choice for a production site. This guide uses Let’s Encrypt, which requires a publicly resolvable domain for its HTTP validation.

Why does this guide use PHP 8.3 on Rocky Linux 8?

Rocky’s base PHP streams may not provide the newest practical PHP branch for a fresh CMS deployment. The Remi 8.3 stream supplies a maintained PHP version while keeping the standard Rocky PHP-FPM service and socket arrangement.

Does Backdrop need MariaDB, or can it use MySQL?

Backdrop supports MySQL-compatible databases, including MariaDB. The dedicated database and local-only user in this guide keep the site’s privileges separate from other applications on the VPS.

Which directory must be included in backups?

Back up the MariaDB database and /var/www/backdrop/files, which contains uploaded media and generated assets. The application code and settings.php should also be retained, but never expose the settings file through the web server.

Samrat Ghosh
Written by

Samrat Ghosh

Founder & Infrastructure Engineer

Samrat Ghosh is the founder of VPSLake, where he builds and runs the remote desktop and VPS hosting infrastructure the company is built on. He writes hands-on guides about RDP, Windows Server, VPS management and secure remote access - the practical documentation he wishes had…

Previous Article

How to Install Backdrop CMS with LEMP on AlmaLinux 8

Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨