A LEMP stack — Linux, Nginx, MySQL (or MariaDB), and PHP — is one of the most common foundations for hosting WordPress, Laravel, and other PHP applications. On RHEL 8, each component is available from the default AppStream repository using module streams, giving you fine-grained control over which PHP version you install without relying on third-party repositories. This tutorial walks through installing and configuring all four components, connecting Nginx to PHP-FPM via a Unix socket, and verifying the stack with a phpinfo() page. SELinux contexts and firewalld rules are included at every stage so the stack works correctly in RHEL 8’s default enforcing environment.
Prerequisites
- RHEL 8 server with a sudo-capable user
- Active RHEL subscription or CentOS/Rocky Linux 8 equivalent
- Ports 80 and 443 available
firewalldactive and running- SELinux in enforcing mode
Step 1 — Install and Start Nginx
Install Nginx from the AppStream and enable it as a persistent service.
sudo dnf install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
curl -s http://localhost | grep -i nginx
Step 2 — Install and Secure MySQL (or MariaDB)
RHEL 8 AppStream provides both MySQL 8.0 and MariaDB 10.3 module streams. This example uses MySQL 8.0. Run the secure installation script to set a root password and remove test accounts.
# Enable the MySQL 8.0 module stream
sudo dnf module enable -y mysql:8.0
sudo dnf install -y mysql-server
sudo systemctl enable mysqld
sudo systemctl start mysqld
sudo systemctl status mysqld
# Secure the installation
sudo mysql_secure_installation
# Follow prompts: set root password, remove anonymous users,
# disallow remote root login, remove test database
# Verify login
sudo mysql -u root -p -e "SHOW DATABASES;"
For MariaDB instead, substitute mysql:8.0 with mariadb:10.5 and the package name with mariadb-server.
Step 3 — Install PHP 8.0 via the AppStream Module
RHEL 8 AppStream ships PHP as a module stream. Select the 8.0 stream and install the common profile, which includes PHP-FPM and the most frequently needed extensions.
sudo dnf module reset php
sudo dnf module enable -y php:8.0
sudo dnf module install -y php:8.0/common
# Install additional extensions for WordPress / general PHP apps
sudo dnf install -y php-mysqlnd php-gd php-xml php-mbstring
php-opcache php-json php-curl php-zip
php -v
sudo systemctl enable php-fpm
sudo systemctl start php-fpm
sudo systemctl status php-fpm
Step 4 — Configure Nginx to Pass PHP Requests to PHP-FPM
PHP-FPM by default listens on a Unix socket at /run/php-fpm/www.sock. Create a server block for your site that passes .php requests to that socket.
sudo mkdir -p /var/www/example.com/html
sudo chown -R nginx:nginx /var/www/example.com
sudo tee /etc/nginx/conf.d/example.com.conf <<'EOF'
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /.ht {
deny all;
}
}
EOF
sudo nginx -t && sudo systemctl reload nginx
Step 5 — Apply SELinux Contexts to the Web Root
On RHEL 8 with SELinux enforcing, the web root must carry the httpd_sys_content_t context so Nginx and PHP-FPM can read files. Directories where PHP writes (uploads, cache) need the writable variant httpd_sys_rw_content_t.
sudo semanage fcontext -a -t httpd_sys_content_t
"/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com
# Allow Nginx to connect to PHP-FPM socket
sudo setsebool -P httpd_can_network_connect on
# If using MySQL over the network
sudo setsebool -P httpd_can_network_connect_db on
# Verify contexts
ls -lZ /var/www/example.com/html/
Step 6 — Create a phpinfo() Test Page and Verify the Stack
Drop a PHP info page into the document root, verify it renders through Nginx and PHP-FPM, then remove it before going to production.
sudo tee /var/www/example.com/html/info.php <<'EOF'
EOF
sudo chown nginx:nginx /var/www/example.com/html/info.php
# Restore SELinux context on the new file
sudo restorecon /var/www/example.com/html/info.php
curl -s http://localhost/info.php | grep -E "PHP Version|mysql|opcache"
# Remove the info page when done — it exposes server internals
sudo rm /var/www/example.com/html/info.php
Conclusion
You now have a fully functional LEMP stack running on RHEL 8 with Nginx serving static files, PHP-FPM handling PHP execution via a Unix socket, and MySQL 8.0 storing application data. The AppStream module system means you can switch PHP versions with a single dnf module switch-to command and a service restart, without adding third-party repositories. SELinux file contexts and the httpd_can_network_connect boolean keep the stack secure by default. To install WordPress on top of this stack, create a database and user in MySQL, download the WordPress archive to the document root, and run through the web-based installer.
Next steps: How to Configure Nginx FastCGI Caching on RHEL 8, How to Set Up Varnish Cache as a Reverse Proxy on RHEL 8, and How to Install and Configure OpenLiteSpeed Web Server on RHEL 8.