LAMP Stack

Table of contents

  1. Overview
  2. Install System Dependencies
  3. Install Apache
  4. Install MySQL/MariaDB
  5. Install PHP
  6. Configure Apache and PHP
  7. Install phpMyAdmin
  8. Install Composer
  9. Install Node.js & NPM
  10. Project Setup
  11. Troubleshooting
  12. References


1. Overview Table of Contents

This guide walks through setting up a LAMP stack (Linux, Apache, MySQL/MariaDB, PHP) for deploying PHP applications, including the Chappy.php framework.

Supported operating systems

Family Versions Package manager
Ubuntu 26.04 LTS, 24.04 LTS apt
Debian Debian 13 “trixie” / LMDE 7 “Gigi” apt
RHEL Rocky Linux 10.x, 9.x dnf
  • Commands marked Ubuntu & Debian apply to every apt system above, and commands marked Rocky Linux apply to Rocky 9 and 10 unless noted.
  • Rocky Linux 10 requires an x86-64-v3 CPU (roughly Intel Haswell / AMD Excavator or newer). On a VM, set the CPU type to host or another v3-capable model.

Requirements

  • Apache 2.4
  • PHP 8.3+
  • MySQL or MariaDB
  • Composer
  • Node.js & NPM
  • Git (for cloning the repository)

2. Install System Dependencies Table of Contents

First, update your system and install essential dependencies:

Ubuntu & Debian

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git unzip ca-certificates net-tools


Rocky Linux (RHEL-based)

sudo dnf install -y epel-release
sudo dnf config-manager --set-enabled crb      # Some EPEL packages depend on CRB
sudo dnf update -y
sudo dnf install -y curl wget git unzip net-tools policycoreutils-python-utils

policycoreutils-python-utils provides semanage, which is used for the SELinux steps in Section 10.

3. Install Apache Table of Contents

A. Install Apache and enable it to start on boot:

Ubuntu and Debian

sudo apt install -y apache2
sudo systemctl enable --now apache2


Rocky Linux (RHEL-based)

sudo dnf install -y httpd
sudo systemctl enable --now httpd


B. Open the firewall:

Ubuntu and Debian (only if ufw is enabled)

sudo ufw allow "Apache Full"

Rocky Linux (RHEL-based) (firewalld is on by default)

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload


C. Verify Apache is running:

systemctl status apache2   # Ubuntu & Debian
systemctl status httpd     # Rocky Linux


D. Apache should now be accessible at:

http://localhost


4. Install MySQL/MariaDB Table of Contents

Install one database server, not both. Chappy.php works with either.

OS MariaDB MySQL
Ubuntu 24.04 / 26.04 ✅ Default repos ✅ Default repos
Debian 13 / LMDE 7 ✅ Default repos (recommended) ⚠️ Not in Debian repos. Requires the MySQL APT repository
Rocky Linux 9 / 10 ✅ Default repos ✅ Default repos (AppStream)

If you don’t have a reason to pick MySQL, use MariaDB. It’s available everywhere in this guide without extra repositories.

A. Install the Database Server

MariaDB: Ubuntu & Debian

sudo apt install -y mariadb-server
sudo systemctl enable --now mariadb

MariaDB: Rocky Linux

sudo dnf install -y mariadb-server
sudo systemctl enable --now mariadb

MySQL: Ubuntu

sudo apt install -y mysql-server
sudo systemctl enable --now mysql

MySQL: Rocky Linux

sudo dnf install -y mysql-server
sudo systemctl enable --now mysqld

Verify the installation:

mariadb -V    # MariaDB
mysql -V      # MySQL


B. Secure the Installation

Run the security script for your database:

sudo mariadb-secure-installation     # MariaDB
sudo mysql_secure_installation       # MySQL

The prompts differ slightly between the two. Answer them as follows:

Prompt MariaDB MySQL (Ubuntu) MySQL (Rocky)
Enter current password for root Press Enter — —
VALIDATE PASSWORD COMPONENT — n (see note) n (see note)
Switch to unix_socket authentication n (root already uses it) — —
Set / change root password n Skipped (uses auth_socket) Required: set one
Remove anonymous users Y Y Y
Disallow root login remotely Y Y Y
Remove test database Y Y Y
Reload privilege tables Y Y Y

Notes

  • VALIDATE PASSWORD COMPONENT: Choosing y enforces password strength rules and can cause ERROR 1819 (HY000) during the phpMyAdmin install. If you do enable it, level 1 (MEDIUM) is a good balance.
  • Root stays on socket authentication for MariaDB and for MySQL on Ubuntu. That means root logs in with sudo and no password, and cannot log into phpMyAdmin. This is intentional: you’ll create a dedicated application user in the next step and use that for your app and for phpMyAdmin.

When finished you should see a message like:

All done! If you've completed all of the above steps, your installation should now be secure.


C. Create the Application Database and User

Log in as root:

sudo mariadb           # MariaDB (all distros)
sudo mysql             # MySQL on Ubuntu
mysql -u root -p       # MySQL on Rocky Linux

Create a database and a user for your app (replace the names and password):

CREATE DATABASE my_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'my_app_user'@'localhost' IDENTIFIED BY 'your-secure-password';
GRANT ALL PRIVILEGES ON my_app.* TO 'my_app_user'@'localhost';
EXIT;

Test the new login:

mysql -u my_app_user -p my_app

These are the values you’ll put in DB_DATABASE, DB_USER, and DB_PASSWORD in your .env file (Section 10C).

D. Optional: Give Root a Password

Only do this if you specifically need password login for root. The application user above is the recommended approach.

MariaDB (keeps socket login and adds a password):

ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket OR mysql_native_password USING PASSWORD('your-secure-password');

MySQL on Ubuntu:

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'your-secure-password';

⚠️ Older guides use IDENTIFIED WITH mysql_native_password. That plugin is disabled by default in MySQL 8.4 and removed in MySQL 9, so use caching_sha2_password with MySQL.

Verify:

SELECT user, host, plugin FROM mysql.user;


5. Install PHP Table of Contents

Chappy.php requires PHP 8.3 or newer. On Ubuntu and Debian, the PHP in the default repositories already meets that, so no third-party repository is needed. Rocky Linux uses the Remi repository.

OS PHP version installed
Ubuntu 24.04 8.3
Ubuntu 26.04 8.5
Debian 13 / LMDE 7 8.4
Rocky Linux 9 / 10 (Remi) 8.4

A. Ubuntu & Debian

sudo apt install -y php php-cli php-mbstring php-xml php-curl php-zip php-mysql php-sqlite3 php-bcmath php-intl php-gd libapache2-mod-php sqlite3

These version-independent package names install whatever PHP version your release ships, so the same command works on every Ubuntu and Debian version in this guide.


B. Rocky Linux (RHEL-based)

sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-$(rpm -E %rhel).rpm
sudo dnf module reset php -y
sudo dnf module enable php:remi-8.4 -y      # Enables PHP 8.4 from Remi repo
sudo dnf install -y php php-cli php-fpm php-mbstring php-xml php-curl php-zip php-mysqlnd php-pdo php-bcmath php-gd php-opcache php-intl php-soap
sudo systemctl enable --now php-fpm

$(rpm -E %rhel) expands to 9 or 10, so the same command works on both Rocky versions. On Rocky, Apache runs PHP through PHP-FPM rather than mod_php, which matters when you change php.ini (Section 6).


C. Verify installation:

php -v


6. Configure Apache and PHP Table of Contents

Restart Apache to apply PHP settings:

sudo systemctl restart apache2   # Ubuntu & Debian
sudo systemctl restart httpd     # Rocky Linux

Test PHP:

  • Create a test file:
    echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
    
  • Open in a browser:
    http://localhost/info.php
    
  • Remove the file after testing:
    sudo rm /var/www/html/info.php
    


Configure upload size for profile image upload support. Edit the file:

Ubuntu & Debian

The path includes your PHP version (for example 8.3, 8.4, or 8.5). Check it with php -v, then edit:

sudo vi /etc/php/<version>/apache2/php.ini

Rocky Linux (RHEL-based)

sudo vi /etc/php.ini

Then modify the following settings:

Setting What it controls Safe recommended value
upload_max_filesize Max size of a single uploaded file 5M (or 10M if high-res image uploads)
post_max_size Max size of total POST body (form fields + files) 8M (or 15M if upload_max_filesize is 10M)
max_execution_time Max script run time (seconds) 30 to 60
memory_limit Max memory a script can use 128M (or 256M for image-heavy apps)

These values should be set depending on what type of files are being uploaded. Files such as videos should be much higher. post_max_size should be greater than upload_max_filesize. Otherwise, you will get a corrupted token error instead.

Apply the changes:

sudo systemctl restart apache2                  # Ubuntu & Debian
sudo systemctl restart php-fpm httpd            # Rocky Linux (PHP-FPM must be restarted too)


7. Install phpMyAdmin Table of Contents

phpMyAdmin provides a web interface to manage MySQL or MariaDB databases.

A. Install phpMyAdmin

Ubuntu & Debian

sudo apt install -y phpmyadmin

During installation:

  • Select apache2 when prompted (press Space to select it, then Enter).
  • Choose Yes to configure the database with dbconfig-common.
  • Set a phpMyAdmin password (or leave blank to generate one).
  • If you get ERROR 1819 (HY000), see the Troubleshooting section.

The package enables its own Apache config, so no symlink is needed. Restart Apache:

sudo systemctl restart apache2


Rocky Linux (RHEL-based)

sudo dnf install -y phpMyAdmin
# If the package isn't found:
sudo dnf --enablerepo=remi install -y phpMyAdmin
sudo systemctl restart httpd

On Rocky, phpMyAdmin is only reachable from the server itself by default. To allow access from another machine, edit /etc/httpd/conf.d/phpMyAdmin.conf and add Require ip your_ip_address next to Require local, then restart httpd.

B. Verify phpMyAdmin Installation

Open your browser and visit:

http://localhost/phpmyadmin

Log in with the application user you created in Section 4C (for example my_app_user). root cannot log in through phpMyAdmin while it uses socket authentication. That’s expected.


8. Install Composer Table of Contents

Composer is required to manage PHP dependencies.

A. Download and Install Composer

cd ~/
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer


B. Verify Installation

composer -V


9. Install Node.js & NPM Table of Contents

Use NodeSource to install the latest LTS Node.js version.

A. Add Node.js Repository

Ubuntu and Debian

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo bash -

Rocky Linux (RHEL-based)

curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -


B. Install Node.js & NPM

Ubuntu and Debian

sudo apt install -y nodejs

Rocky Linux (RHEL-based)

sudo dnf install -y nodejs


C. Verify Installation

node -v
npm -v


10. Project Setup Table of Contents

A. Navigate to your user’s home directory, install dependencies, then move to final location:

Create your project and replace my-app with the name of your project.

cd ~/
composer create-project chappy-php/chappy-php my-app
sudo mv my-app /var/www/html
cd /var/www/html/my-app


B. Set proper permissions:

Ubuntu and Debian

sudo chown -R your-username:www-data /var/www/html/my-app

Rocky Linux (RHEL-based)

sudo chown -R your-username:apache /var/www/html/my-app

All distros

sudo find /var/www/html/my-app -type d -exec chmod 755 {} \;
sudo find /var/www/html/my-app -type f -exec chmod 644 {} \;
sudo chmod -R 775 /var/www/html/my-app/storage

The storage directory needs group write access for logs and uploads.

C. Project Configuration

Open your preferred IDE (We use VSCode) and edit the .env file:

  • Set APP_DOMAIN to /.
  • For security purposes ensure DB_LOG_PARAMS is set to none instead of full.
  • Set LOGGING environmental variable as appropriate for your use. In production we recommend info to prevent excessive logging.
  • Update the database section with the database and user from Section 4C:
    # Set to mysql or mariadb
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=my_app
    DB_USER=my_app_user
    DB_PASSWORD=your-secure-password
    


D. Apache Virtual Host Configuration

Run the following command to create a new Apache configuration file:

Ubuntu and Debian

sudo vi /etc/apache2/sites-available/my-app.conf

Paste the following content into the file (adjust ServerName to your actual IP or domain):

<VirtualHost *:80>
    ServerName localhost
    ServerAlias your_ip_address my-app.local
    DocumentRoot /var/www/html/my-app

    <Directory /var/www/html/my-app>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Save and exit (ESC then :wq).

Rocky Linux (RHEL-based)

For .htaccess files to work correctly on Rocky Linux, Apache needs AllowOverride All. Options FollowSymLinks lets rewrite rules work.

sudo vi /etc/httpd/conf.d/my-app.conf

Paste the following content into the file (replace my-app.local and your_ip_address with information relevant for your case):

<VirtualHost *:80>
    ServerName localhost
    ServerAlias your_ip_address my-app.local
    DocumentRoot /var/www/html/my-app

    <Directory /var/www/html/my-app>
        AllowOverride All
        Require all granted
        Options FollowSymLinks
    </Directory>

    ErrorLog /var/log/httpd/my-app-error.log
    CustomLog /var/log/httpd/my-app-access.log combined
</VirtualHost>

Save and exit (ESC then :wq).

Update /etc/hosts (For Custom Domain)

If you want to access your site using http://my-app.local, you can edit your /etc/hosts file:

sudo vi /etc/hosts

Example configuration:

127.0.0.1       localhost my-app.local
127.0.1.1       ubuntu-vm
your_ip_addr    my-app.local


E. Enable the Site:

Ubuntu and Debian

# Enable mod_rewrite first
sudo a2enmod rewrite

# Disable the default site so it doesn't catch requests by IP
sudo a2dissite 000-default.conf

# Then enable the VirtualHost
sudo a2ensite my-app.conf
sudo apache2ctl configtest
sudo systemctl restart apache2


Rocky Linux (RHEL-based)

mod_rewrite is already enabled on Rocky Linux (see Troubleshooting D if rewrites aren’t working).

1. Fix SELinux Contexts

Files moved from your home directory keep their old SELinux label, so Apache can’t read them. Reset the labels:

sudo restorecon -Rv /var/www/html/my-app

2. Make Storage Writable

Mark storage as writable by Apache. This is persistent and survives reboots and relabels:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/my-app/storage(/.*)?"
sudo restorecon -Rv /var/www/html/my-app/storage

📁 If you’re using other writable paths, repeat these steps for those as well.

3. Allow Apache to Connect to the Database

Because DB_HOST=127.0.0.1 connects over TCP, SELinux must allow Apache to reach the database port:

sudo setsebool -P httpd_can_network_connect_db 1

Only if your app makes outbound connections (external APIs, SMTP, etc.):

sudo setsebool -P httpd_can_network_connect 1
sudo setsebool -P httpd_can_sendmail 1

Now check the config and restart Apache:

sudo apachectl configtest
sudo systemctl restart httpd


F. Final Steps

Run migrations:

cd /var/www/html/my-app
php console migrate

Your project should now be accessible at:

http://<your_ip_address>


11. Troubleshooting Table of Contents

A. Database Issues

  • ERROR 1819 (HY000) during phpMyAdmin installation: Your password does not meet MySQL’s VALIDATE PASSWORD policy. Use a stronger password, or remove the component:
    UNINSTALL COMPONENT 'file://component_validate_password';
    
  • Access denied for user 'root'@'localhost' in phpMyAdmin: Expected when root uses socket authentication. Log in with your application user (Section 4C), or see Section 4D.
  • Plugin 'mysql_native_password' is not loaded: You’re on MySQL 8.4+. Use caching_sha2_password instead (Section 4D).
  • App can’t connect to the database on Rocky Linux: Run sudo setsebool -P httpd_can_network_connect_db 1 (Section 10E).

B. phpMyAdmin 403 Forbidden (Rocky Linux)

phpMyAdmin on Rocky only allows local access by default. Edit /etc/httpd/conf.d/phpMyAdmin.conf, add Require ip your_ip_address alongside Require local, and restart httpd.

C. PHP Settings Not Taking Effect (Rocky Linux)

Rocky runs PHP through PHP-FPM, so restarting Apache alone doesn’t reload php.ini:

sudo systemctl restart php-fpm


D. mod_rewrite for Rocky Linux (RHEL)

mod_rewrite is loaded by default from /etc/httpd/conf.modules.d/00-base.conf. Confirm it’s active:

httpd -M | grep rewrite

If nothing is returned, make sure this line exists and isn’t commented out in /etc/httpd/conf.modules.d/00-base.conf:

LoadModule rewrite_module modules/mod_rewrite.so

If the module is loaded but rewrites still fail, check that your VirtualHost has AllowOverride All. Then restart Apache:

sudo systemctl restart httpd


E. Finding SELinux Denials (Rocky Linux)

If you get 403 errors or write failures that permissions don’t explain, check for SELinux denials:

sudo ausearch -m avc -ts recent


F. Rocky Linux 10 Won’t Boot or Install

Rocky Linux 10 requires an x86-64-v3 CPU. On older hardware, use Rocky Linux 9. On a VM, change the CPU type to host (or another v3-capable model).

12. References Table of Contents

A. How To Install Linux, Apache, MySQL, PHP (LAMP) Stack on Ubuntu - Digital Ocean

B. How To Install and Secure phpMyAdmin on Ubuntu - Digital Ocean

C. How to Deploy a Laravel App Using Apache and MySQL

D. Remi’s RPM Repository - Configuration Wizard

E. Rocky Linux Releases