| Tested on | Rocky Linux 10.2 (Red Quartz) |
|---|---|
| Package | httpd 2.4.63mariadb-server 10.11.18php 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.
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.
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:
cat /etc/os-releaseSample 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.
dnf info httpd mariadb-server php php-fpmSample 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 : appstreamThe 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:
sudo dnf install httpdRecord the installed Apache version:
httpd -vSample output:
Server version: Apache/2.4.63 (Rocky Linux)Enable and start the service with systemctl command:
sudo systemctl enable --now httpdConfirm the unit is running:
systemctl status httpdSample 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:
sudo firewall-cmd --permanent --add-service=httpReload so the runtime configuration picks up the change:
sudo firewall-cmd --reloadConfirm that HTTP is allowed in both the active runtime and permanent configurations:
sudo firewall-cmd --query-service=httpsudo firewall-cmd --permanent --query-service=httpSample output:
yes
yesRed Hat distinguishes runtime and permanent firewalld configurations; permanent verification requires the --permanent option.
Request the default site locally with curl command:
curl -I http://127.0.0.1Sample 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:
sudo ss -lntp | grep ':80'Sample 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.
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:
sudo dnf install mariadb-serverRecord the installed MariaDB version:
mariadb --versionSample output:
mariadb Ver 15.1 Distrib 10.11.18-MariaDB, for Linux (x86_64) using EditLine wrapperEnable and start MariaDB:
sudo systemctl enable --now mariadbConfirm the service:
systemctl status mariadbSample 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:
sudo mariadb-secure-installationOn 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_socketauthentication — retain it forroot@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
testdatabase - Reload privilege tables — yes
Verify local administrative access:
sudo mariadbA 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:
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:
sudo dnf install php php-cli php-fpm php-mysqlndMany 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:
sudo dnf install php-mbstring php-xml php-gd php-intl php-opcachePrint the installed PHP version:
php -vList loaded modules and confirm the MySQL drivers are present:
php -mSample output:
[PHP Modules]
...
mysqli
mysqlnd
pdo_mysql
...Show where php.ini and drop-in files live:
php --iniSample output:
Configuration File (php.ini) Path: /etc
Loaded Configuration File: /etc/php.ini
Scan for additional .ini files in: /etc/php.dThe mysqlnd and pdo_mysql entries matter for the database test later.
Verify Apache and PHP-FPM integration
Enable and start PHP-FPM:
sudo systemctl enable --now php-fpmValidate the FPM configuration syntax:
php-fpm -tSample output:
[22-Jul-2026 08:02:13] NOTICE: configuration file /etc/php-fpm.conf test is successfulTest the Apache configuration:
sudo apachectl configtestSample output:
Syntax OKRestart both services so Apache picks up the FPM proxy configuration:
sudo systemctl restart php-fpm httpdKey integration files on a default install:
/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.sockCreate a small PHP test page under the Apache document root:
echo '<?php echo "PHP " . PHP_VERSION . " via " . php_sapi_name(); ?>' | sudo tee /var/www/html/test.phpRequest it locally:
curl --fail-with-body -sS http://127.0.0.1/test.phpSample output:
PHP 8.3.31 via fpm-fcgiThe 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:
sudo rm /var/www/html/test.phpIf 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:
Client → Apache → PHP-FPM → PHP MySQL extension → MariaDBCreate 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.
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');
SQLThe command exits silently when the objects are created successfully.
Create a PDO test script:
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';
}
EOFRequest the script through Apache:
curl --fail-with-body -sS http://127.0.0.1/db-test.phpSample output:
Database value: stack-okThat 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:
sudo rm /var/www/html/db-test.phpDrop the temporary database and user:
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:
systemctl is-active httpd php-fpm mariadbSample output:
active
active
activeConfirm they are enabled for boot:
systemctl is-enabled httpd php-fpm mariadbSample output:
enabled
enabled
enabledReview listening ports:
sudo ss -lntp | grep -E ':80|:3306'Sample 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:
sudo journalctl -u httpdsudo journalctl -u php-fpmsudo journalctl -u mariadbReferences
- Red Hat Enterprise Linux 10 — Deploying web servers and reverse proxies
- Red Hat Enterprise Linux 10 — Installing and using dynamic programming languages
- Red Hat Enterprise Linux 10 — Using MariaDB
- Rocky Linux documentation — Web Servers: Apache
- Rocky Linux documentation — PHP and PHP-FPM
- Apache HTTP Server documentation
- MariaDB documentation
- PHP-FPM documentation
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.

