Install LAMP Stack on Rocky Linux, AlmaLinux, and RHEL

Install Apache, MariaDB, PHP, and PHP-FPM on Rocky Linux, RHEL, AlmaLinux, or Oracle Linux, then verify the complete LAMP stack with a PHP database test.

Published

Updated

Read time 11 min read

Reviewed byDeepak Prasad

Install LAMP stack on Rocky Linux banner with Apache MariaDB and PHP logos and terminal motif
Tested on Rocky Linux 10.2 (Red Quartz)
Package httpd 2.4.63
mariadb-server 10.11.18
php 8.3.31
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege sudo or root
Scope Install LAMP Stack on Rocky Linux, AlmaLinux, and RHEL, including Linux, RHEL, AlmaLinux, Oracle Linux, and then verify the complete LAMP stack.
Related guides Add Linux To Windows Ad Domain Realm
Boom Boot Linux Lvm Snapshot Rhel 8 Linux
Boot In Single User Mode Rhel Centos 8 Linux
Boot Rescue Mode Iso Rhel Centos 7
Boot With Old Kernel Version Rhel 8 Grubby

A LAMP stack combines Linux, Apache HTTP Server, MariaDB, and PHP to serve dynamic web applications from distribution packages. This guide installs and integrates those components on Rocky Linux using native httpd, mariadb-server, and php-fpm packages, opens HTTP through firewalld, and finishes with a PHP script that reads a row from a local MariaDB database.

The procedure also applies to AlmaLinux, RHEL, Oracle Linux, and CentOS Stream when the same packages are available in your enabled repositories.

NOTE
This guide installs the default repository PHP version for your release. It does not use Remi packages, EPEL-provided alternatives, a manually selected PHP module stream, or the versioned php8.4-* package family. For PHP 8.4 specifically, see install PHP 8.4 on Enterprise Linux. For an existing PHP 8.3 deployment, use upgrade PHP 8.3 to 8.4 instead of treating this page as a version migration.
NOTE
Prefer Nginx over Apache? Follow install LEMP stack on Rocky Linux for the Nginx, MariaDB, and PHP-FPM workflow. This article keeps Apache integration, PHP-FPM checks, and Apache-specific troubleshooting in one place.

Prerequisites

  • Rocky Linux, AlmaLinux, RHEL, Oracle Linux, or CentOS Stream with BaseOS and AppStream enabled.
  • sudo command or root access for packages, services, and firewall changes.
  • Outbound access to distribution repositories.
  • A host without both MariaDB and MySQL server packages already installed.

Check the available LAMP package versions

Package versions depend on your distribution major release and repository metadata—not on this article’s publication date.

Identify the operating system:

bash
cat /etc/os-release

Sample output:

output
NAME="Rocky Linux"
VERSION="10.2 (Red Quartz)"
VERSION_ID="10.2"
PLATFORM_ID="platform:el10"
PRETTY_NAME="Rocky Linux 10.2 (Red Quartz)"

Look up the core LAMP packages before you install them. Package discovery and installs use the dnf command.

bash
dnf info httpd mariadb-server php php-fpm

Sample output:

output
Available Packages
Name         : httpd
Version      : 2.4.63
Release      : 13.el10_2.4
Repository   : appstream
...
Name         : mariadb-server
Version      : 10.11.18
Release      : 1.el10_2
Repository   : appstream
...
Name         : php
Version      : 8.3.31
Release      : 1.el10_2
Repository   : appstream
...
Name         : php-fpm
Version      : 8.3.31
Release      : 1.el10_2
Repository   : appstream

The Repository field should point at AppStream or another enabled distribution repo—not a third-party stream you did not deliberately enable.

Platform generation Version handling
EL 8 and EL 9 Additional application versions may appear through DNF modules
EL 10 Uses regular or versioned RPM packages rather than the older module workflow for the default PHP stack
This guide Installs the default supported repository versions shown by dnf info

This guide uses the unversioned mariadb-server package, which provides MariaDB 10.11 on the tested host. EL 10.2 also offers MariaDB 11.8 through the separate mariadb11.8-server package, but that alternative is outside this baseline stack procedure. Red Hat documents both package families and confirms that only one MariaDB stream can be installed from native RPMs at a time.


Install and test Apache HTTP Server

Install the Apache HTTP Server package from AppStream:

bash
sudo dnf install httpd

Record the installed Apache version:

bash
httpd -v

Sample output:

output
Server version: Apache/2.4.63 (Rocky Linux)

Enable and start the service with systemctl command:

bash
sudo systemctl enable --now httpd

Confirm the unit is running:

bash
systemctl status httpd

Sample output:

output
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
     Active: active (running)

When firewalld is active, allow HTTP through the default zone. See the firewalld reference for --permanent, --reload, and --zone= options when an interface uses a non-default zone. This guide opens port 80 only—not HTTPS, which belongs in a separate TLS configuration article.

Add the HTTP service to the permanent ruleset:

bash
sudo firewall-cmd --permanent --add-service=http

Reload so the runtime configuration picks up the change:

bash
sudo firewall-cmd --reload

Confirm that HTTP is allowed in both the active runtime and permanent configurations:

bash
sudo firewall-cmd --query-service=http
bash
sudo firewall-cmd --permanent --query-service=http

Sample output:

output
yes
yes

Red Hat distinguishes runtime and permanent firewalld configurations; permanent verification requires the --permanent option.

Request the default site locally with curl command:

bash
curl -I http://127.0.0.1

Sample output:

output
HTTP/1.1 403 Forbidden
Date: Wed, 22 Jul 2026 02:32:10 GMT
Server: Apache/2.4.63 (Rocky Linux)

A default RHEL-family Apache installation can return 403 Forbidden before an index file exists. That response still confirms that HTTP reached Apache. An empty reply or connection refused means the service still needs attention.

The localhost request verifies Apache itself. To verify routing and the host firewall, request http://<server-ip>/ from another machine on the network.

Check that Apache is listening with the ss command:

bash
sudo ss -lntp | grep ':80'

Sample output:

output
LISTEN 0 511 *:80 *:* users:(("httpd",pid=23965,fd=4))

Install and initialize MariaDB

This guide uses MariaDB from AppStream because it completes the stack with distribution packages alone.

NOTE
You can install MySQL instead of MariaDB when your organization standardizes on Oracle MySQL, but do not install both database servers on one host. On native EL 10 repositories, MySQL 8.4 uses the mysql8.4-server package and mysqld.service. Oracle’s separate MySQL Community repository uses package names such as mysql-community-server. Native MariaDB and MySQL server RPMs conflict and should not be installed together.

Install the server package:

bash
sudo dnf install mariadb-server

Record the installed MariaDB version:

bash
mariadb --version

Sample output:

output
mariadb  Ver 15.1 Distrib 10.11.18-MariaDB, for Linux (x86_64) using  EditLine wrapper

Enable and start MariaDB:

bash
sudo systemctl enable --now mariadb

Confirm the service:

bash
systemctl status mariadb

Sample output:

output
● mariadb.service - MariaDB 10.11 database server
     Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; preset: disabled)
     Active: active (running)

Optionally review the default MariaDB accounts and authentication settings with the interactive helper:

bash
sudo mariadb-secure-installation

On MariaDB 10.11, local root@localhost access normally uses unix_socket authentication already, so there is usually no need to create a separate database root password. The script remains useful for removing anonymous accounts and the default test database.

Retain unix_socket authentication for the MariaDB root account in this guide. This allows subsequent administrative commands to use sudo mariadb without storing or entering a database root password.

If the script prompts you, expect questions similar to:

  • Current root password — press Enter on a fresh install when no password is set yet
  • unix_socket authentication — retain it for root@localhost; do not switch to password authentication for this guide
  • Remove anonymous users — yes for most lab and production hosts
  • Disallow root login remotely — yes when only local administration is required
  • Remove test database — yes unless you rely on the default test database
  • Reload privilege tables — yes

Verify local administrative access:

bash
sudo mariadb

A MariaDB [(none)]> prompt confirms Unix-socket authentication works. Type EXIT; to leave the shell.

When your policy requires password-based root authentication instead, replace later sudo mariadb commands with mariadb -u root -p. For example, the test-database command would begin with mariadb -u root -p <<'SQL', and cleanup would use:

bash
mariadb -u root -p -e \
  "DROP DATABASE IF EXISTS lamp_test;
   DROP USER IF EXISTS 'lamp_app'@'localhost';"

Port 3306 does not need to be opened in firewalld for the PHP-to-database test later—PHP-FPM and MariaDB communicate on the same host.


Install PHP and required extensions

Modern Apache integrations on Enterprise Linux use PHP-FPM over FastCGI. You will not enable legacy mod_php or look for a libphp module in this workflow.

Install the core PHP packages:

bash
sudo dnf install php php-cli php-fpm php-mysqlnd

Many web applications also need common extension RPMs:

Requirement Package
Multibyte text php-mbstring
XML handling php-xml
Image processing php-gd
Internationalization php-intl
Opcode cache php-opcache

Install the optional set when your application needs them:

bash
sudo dnf install php-mbstring php-xml php-gd php-intl php-opcache

Print the installed PHP version:

bash
php -v

List loaded modules and confirm the MySQL drivers are present:

bash
php -m

Sample output:

output
[PHP Modules]
...
mysqli
mysqlnd
pdo_mysql
...

Show where php.ini and drop-in files live:

bash
php --ini

Sample output:

output
Configuration File (php.ini) Path: /etc
Loaded Configuration File:         /etc/php.ini
Scan for additional .ini files in: /etc/php.d

The mysqlnd and pdo_mysql entries matter for the database test later.


Verify Apache and PHP-FPM integration

Enable and start PHP-FPM:

bash
sudo systemctl enable --now php-fpm

Validate the FPM configuration syntax:

bash
php-fpm -t

Sample output:

output
[22-Jul-2026 08:02:13] NOTICE: configuration file /etc/php-fpm.conf test is successful

Test the Apache configuration:

bash
sudo apachectl configtest

Sample output:

output
Syntax OK

Restart both services so Apache picks up the FPM proxy configuration:

bash
sudo systemctl restart php-fpm httpd

Key integration files on a default install:

text
/etc/httpd/conf.d/php.conf      Apache FastCGI proxy to PHP-FPM
/etc/php-fpm.conf               Main FPM configuration
/etc/php-fpm.d/www.conf         Default pool; socket at /run/php-fpm/www.sock

Create a small PHP test page under the Apache document root:

bash
echo '<?php echo "PHP " . PHP_VERSION . " via " . php_sapi_name(); ?>' | sudo tee /var/www/html/test.php

Request it locally:

bash
curl --fail-with-body -sS http://127.0.0.1/test.php

Sample output:

output
PHP 8.3.31 via fpm-fcgi

The fpm-fcgi SAPI confirms Apache forwarded the request to PHP-FPM rather than returning raw source text.

Remove the test file when you are done with this section:

bash
sudo rm /var/www/html/test.php

If you temporarily use phpinfo() for debugging, delete that file immediately afterward—it exposes environment details.


Test the complete PHP-to-MariaDB stack

This step proves the full path:

text
Client → Apache → PHP-FPM → PHP MySQL extension → MariaDB

Create a dedicated database and application user. Do not embed the MariaDB root password in PHP. The password below is a temporary lab credential only.

The following administrative commands assume that you retained Unix-socket authentication for the MariaDB root account.

bash
sudo mariadb <<'SQL'
CREATE DATABASE lamp_test;

CREATE USER 'lamp_app'@'localhost'
    IDENTIFIED BY 'LampAppPass_2026';

GRANT SELECT ON lamp_test.*
    TO 'lamp_app'@'localhost';

CREATE TABLE lamp_test.items (
    id INT PRIMARY KEY,
    label VARCHAR(64)
);

INSERT INTO lamp_test.items
    VALUES (1, 'stack-ok');
SQL

The command exits silently when the objects are created successfully.

Create a PDO test script:

bash
sudo tee /var/www/html/db-test.php > /dev/null <<'EOF'
<?php
$dsn = 'mysql:host=localhost;dbname=lamp_test;charset=utf8mb4';
$user = 'lamp_app';
$pass = 'LampAppPass_2026';
try {
    $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
    $row = $pdo->query('SELECT label FROM items WHERE id = 1')->fetchColumn();
    echo 'Database value: ' . $row;
} catch (PDOException $e) {
    http_response_code(500);
    echo 'Database error';
}
EOF

Request the script through Apache:

bash
curl --fail-with-body -sS http://127.0.0.1/db-test.php

Sample output:

output
Database value: stack-ok

That response confirms PHP reached MariaDB with the limited application account.

Remove lab-only resources when testing is complete—the test script, application user, and database are not for production use:

bash
sudo rm /var/www/html/db-test.php

Drop the temporary database and user:

bash
sudo mariadb -e "DROP DATABASE IF EXISTS lamp_test; DROP USER IF EXISTS 'lamp_app'@'localhost';"

Use your own application database name, user, and grants in production.


Verify services and reboot persistence

Confirm all three stack services are active:

bash
systemctl is-active httpd php-fpm mariadb

Sample output:

output
active
active
active

Confirm they are enabled for boot:

bash
systemctl is-enabled httpd php-fpm mariadb

Sample output:

output
enabled
enabled
enabled

Review listening ports:

bash
sudo ss -lntp | grep -E ':80|:3306'

Sample output:

output
LISTEN 0 80 0.0.0.0:3306 0.0.0.0:* users:(("mariadbd",pid=23732,fd=18))
LISTEN 0 511 *:80 *:* users:(("httpd",pid=23965,fd=4))

After a reboot, repeat a quick HTTP request and the database test if you kept the lab script. On the tested host, enabled units started automatically and the PHP page continued to return the expected value.

The default /var/www/html document root and a local localhost database connection did not require disabling SELinux on Rocky Linux 10.2. Custom document roots or network database hosts may need separate SELinux context work—outside this baseline install.


Troubleshoot LAMP stack problems

Symptom Main check
Apache page is unreachable systemctl status httpd, port 80 listener, firewalld HTTP service, correct server IP or hostname
Apache fails to start sudo apachectl configtest and sudo journalctl -u httpd
PHP source is displayed php-fpm active, /etc/httpd/conf.d/php.conf loaded, restart httpd after FPM changes
PHP page returns HTTP 500 sudo journalctl -u php-fpm and Apache error log under /var/log/httpd/
PHP extension is missing php -m and install the matching php-* RPM
PHP cannot connect to MariaDB Credentials, database grants, php-mysqlnd installed, socket or localhost host entry
Access denied for user MariaDB user host (localhost vs 127.0.0.1) and GRANT privileges
Database service fails sudo journalctl -u mariadb and /etc/my.cnf.d/
Custom files return 403 File ownership, permissions, Apache <Directory> rules, SELinux file contexts
Stack fails after reboot systemctl is-enabled httpd php-fpm mariadb

Useful log commands—see view logs with journalctl for follow mode and filters.

Recent logs for each stack service:

bash
sudo journalctl -u httpd
bash
sudo journalctl -u php-fpm
bash
sudo journalctl -u mariadb

References


Summary

Install a LAMP stack on Rocky Linux and compatible Enterprise Linux releases by enabling AppStream, installing httpd, mariadb-server, and php-fpm, opening HTTP in firewalld, and hardening MariaDB with mariadb-secure-installation. Apache serves PHP through FastCGI and PHP-FPM—not mod_php. Prove the integration with a small PHP script that reads from a dedicated MariaDB user and database, then remove lab-only test files. For Nginx instead of Apache, use install LEMP stack on Rocky Linux. For PHP 8.4 specifically, follow install PHP 8.4 on Enterprise Linux.


Frequently Asked Questions

1. What does LAMP stand for on Rocky Linux?

Linux, Apache HTTP Server, MariaDB or MySQL, and PHP. This guide uses MariaDB from AppStream and PHP-FPM behind Apache—not legacy mod_php.

2. Does this guide install PHP 8.4?

No. It installs the default supported php and php-fpm packages from your distribution repositories. For native PHP 8.4 on EL 10.2+, follow the install PHP 8.4 on Enterprise Linux guide.

3. Can I use MySQL instead of MariaDB?

Yes, but install only one database server. On native EL 10 repositories, MySQL 8.4 uses the mysql8.4-server package and mysqld.service. Oracle's separate MySQL Community repository uses package names such as mysql-community-server. Do not install native MariaDB and MySQL server packages together on the same host.

4. Why does Apache show PHP source code instead of running it?

PHP is not wired through PHP-FPM. Confirm php-fpm is active, review /etc/httpd/conf.d/php.conf, and restart httpd after fixing the FastCGI proxy configuration.

5. Should I open MariaDB port 3306 in the firewall for this stack?

Not for the workflow here. Apache, PHP-FPM, and MariaDB run on the same server and connect over the local socket or localhost. Open 3306 only when remote database clients are required.

6. How is LAMP different from LEMP on Rocky Linux?

LAMP uses Apache as the web server. LEMP uses Nginx with PHP-FPM. The database and PHP package steps overlap, but web-server integration and troubleshooting differ—see install LEMP stack on Rocky Linux.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on …