This guide shows how to install a reliable LEMP stack — Nginx, MariaDB (or MySQL-compatible server) and PHP-FPM — on RHEL-based systems such as RHEL, Rocky Linux, AlmaLinux and CentOS Stream. You’ll learn which repositories to enable, how to configure PHP-FPM to work with Nginx, basic SELinux and firewall adjustments, and simple checks to confirm everything runs correctly.

Where this applies and what to prepare
These instructions target modern RHEL-family systems (RHEL 8/9, Rocky, Alma, CentOS Stream). Details like PHP module streams and package names can vary by distribution version. Before you begin, have:
- root or sudo access to the server
- network connectivity for package repositories
- a basic firewall policy (firewalld) — if you use a different firewall, adapt the commands
High-level steps
- Update the system and enable common repos (EPEL).
- Install and start Nginx.
- Install and secure MariaDB.
- Install PHP-FPM and necessary extensions, configure pool for Nginx.
- Create an Nginx site configuration to serve PHP via the PHP-FPM socket (or TCP), adjust SELinux and firewall, then verify.
1. Update system and enable EPEL
Keep the system current and install EPEL, which provides extra packages that can be useful.
sudo dnf update -y
sudo dnf install -y epel-release
On RHEL itself you might need a subscription or to enable appropriate repos; on Rocky/Alma/CentOS Stream the epel-release package usually works directly.
2. Install and start Nginx
Install Nginx from the default repositories and enable it to start on boot.
sudo dnf install -y nginx
sudo systemctl enable --now nginx
Quick check:
sudo systemctl status nginx
curl -I http://localhost
3. Install and secure MariaDB
MariaDB is commonly available as mariadb-server. After installation, run the interactive secure script to set a root password and remove test databases.
sudo dnf install -y mariadb-server
sudo systemctl enable --now mariadb
sudo mysql_secure_installation
The mysql_secure_installation script will prompt you to set a root password, remove anonymous users, disallow remote root login, and remove the test database. Answer according to your security needs.
4. Install PHP-FPM and extensions
On RHEL-family systems PHP is provided via AppStream module streams. First list available PHP module streams so you can choose the version you want:
dnf module list php
To install a chosen stream (example shows php:8.1 — pick the stream appropriate for your system), enable the module and install packages:
sudo dnf module enable php:8.1 # choose the stream you need
sudo dnf install -y php-fpm php-mysqlnd php-opcache php-xml php-gd php-mbstring
If you prefer newer PHP releases, the Remi repository is a common source, but enabling third-party repos is optional and outside this basic guide.
Enable and start php-fpm:
sudo systemctl enable --now php-fpm
sudo systemctl status php-fpm
Important PHP-FPM pool settings for Nginx
Edit the default pool file /etc/php-fpm.d/www.conf and ensure ownership and socket settings fit Nginx. Two common options:
- Use a Unix socket (common and efficient): set
listen = /run/php-fpm/www.sock, and make surelisten.ownerandlisten.grouparenginx. - Use a TCP socket (e.g.,
127.0.0.1:9000) if you prefer separation or remote PHP-FPM. If you use TCP, set the SELinux boolean to allow network connections.
Example important lines to check in /etc/php-fpm.d/www.conf:
user = nginx
group = nginx
listen = /run/php-fpm/www.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
After edits, restart PHP-FPM:
sudo systemctl restart php-fpm
5. Configure Nginx to serve PHP
Create a site directory and a simple phpinfo() test page:
sudo mkdir -p /usr/share/nginx/html/example.com
sudo chown -R nginx:nginx /usr/share/nginx/html/example.com
cat <<'EOF' | sudo tee /usr/share/nginx/html/example.com/index.php
<?php phpinfo();
EOF
Create an Nginx server block. Place it in /etc/nginx/conf.d/example.com.conf:
sudo tee /etc/nginx/conf.d/example.com.conf > /dev/null <<'NGINX'
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html/example.com;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
location ~ /\.ht {
deny all;
}
}
NGINX
Test and reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
6. SELinux and firewall adjustments
If SELinux is enabled (check with sestatus), you may need to set file contexts and booleans.
- Give the site directory the web content file context (persistent):
sudo dnf install -y policycoreutils-python-utils # provides semanage if missing
sudo semanage fcontext -a -t httpd_sys_content_t '/usr/share/nginx/html/example.com(/.*)?'
sudo restorecon -Rv /usr/share/nginx/html/example.com
If the application needs writable directories (upload folders, cache), mark them with httpd_sys_rw_content_t instead:
sudo semanage fcontext -a -t httpd_sys_rw_content_t '/usr/share/nginx/html/example.com/storage(/.*)?'
sudo restorecon -Rv /usr/share/nginx/html/example.com/storage
If you configured PHP-FPM to use TCP (e.g., 127.0.0.1:9000), allow Nginx to make network connections:
sudo setsebool -P httpd_can_network_connect on
Firewall (firewalld) — open HTTP and HTTPS:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
7. Verify everything works
Basic service status checks:
sudo systemctl status nginx
sudo systemctl status php-fpm
sudo systemctl status mariadb
Confirm ports are listening:
ss -ltnp | grep -E ':80|:443|:3306'
# or
curl -I http://localhost
curl http://localhost/index.php
Open http://your-server-ip/ or http://example.com/ in a browser. The index.php file should show the PHP information page if PHP-FPM and Nginx are connected correctly.
Notes and practical tips
- If you need a newer PHP version than AppStream provides, consider enabling the Remi repository; follow Remi’s documentation for the appropriate distribution and version.
- Using a Unix socket is usually faster and requires fewer SELinux booleans; using TCP is convenient if PHP-FPM runs on another host or container.
- On RHEL systems with subscriptions, repository names and availability can differ — check your subscription manager and repository list if packages are missing.
- For production, switch the test
phpinfo()file out for your real application, enable HTTPS, and harden MariaDB credentials and network access.
Wrap-up
Following these steps you should have a working LEMP stack suitable for hosting PHP applications on RHEL-family systems. The key decisions are which PHP stream to use and whether to connect PHP-FPM via socket or TCP; both approaches are supported. After the basic setup, focus on hardening (HTTPS, database user privileges) and tuning (PHP-FPM pools, Nginx caching) for your workload.
Read more
- Set Up WireGuard VPN Client on CentOS Stream/RockyLinux/RHEL-based
- How to Install and Configure NGINX server on Ubuntu/Debian
- How to Install and Configure Multi PHP Version on Ubuntu / Debian
- How to Install LAMP stack ( Linux – Apache – MySQL/MariaDB – PHP ) on Debian
- Enable Windows Subsystem for Linux (WSL) on Windows