Reader Stacks

Installing PHP, Apache, MySQL, and phpMyAdmin on Ubuntu

A working LAMP stack setup for Ubuntu — apt package installation, the Apache/MySQL services, and the one phpMyAdmin config step people usually miss.

Installing PHP, Apache, MySQL, and phpMyAdmin on Ubuntu

A LAMP stack (Linux, Apache, MySQL, PHP) is still a common baseline for running PHP applications on a self-managed Ubuntu server — here's a working setup, current as of recent Ubuntu LTS releases.

1. Update package lists

sudo apt update && sudo apt upgrade -y

2. Install Apache

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

3. Install MySQL

sudo apt install mysql-server -y
sudo mysql_secure_installation

mysql_secure_installation walks through setting a root password, removing anonymous users, and disabling remote root login — don't skip this step on anything beyond a throwaway local environment.

4. Install PHP and common extensions

sudo apt install php libapache2-mod-php php-mysql php-mbstring php-xml php-curl -y

The specific extension list depends on what the application needs — a Laravel project typically also needs php-zip, php-bcmath, and php-gd or php-imagick for image handling.

5. Restart Apache to load PHP

sudo systemctl restart apache2

6. Install phpMyAdmin

sudo apt install phpmyadmin -y

During installation, select apache2 when prompted for the web server to configure automatically, and choose whether to let the installer configure the database for phpMyAdmin itself.

The step people miss: enabling the Apache config

If phpMyAdmin was installed separately from Apache, or the automatic prompt was skipped, the Apache config for it needs to be included manually:

sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
sudo a2enconf phpmyadmin
sudo systemctl reload apache2

Without this, /phpmyadmin returns a 404 even though the package installed successfully — a common point of confusion.

Security note for a real server

phpMyAdmin is a high-value administration surface on a public server. For anything beyond local development, restrict access with a real control such as a VPN, firewall/IP allow-list, or an additional authenticated gateway. Moving it to a non-default URL can reduce noise from generic scanners, but obscurity is not an access-control boundary.

Verify the installed PHP version and modules before configuring the app

php -v
php -m
apache2ctl -M | grep php

The Ubuntu repository decides which PHP version the unversioned php packages install. Application requirements should drive whether that repository version is acceptable; do not add a third-party repository merely because a tutorial uses one. After installation, confirm the CLI and Apache are actually using the version and extensions you expect.

Apache needs the right document root for frameworks

A Laravel application's web root is its public/ directory, not the project root. Pointing an Apache virtual host at the whole repository can expose files that should never be web-accessible, including dependency metadata or environment configuration if another server rule is also wrong. A minimal virtual host should set DocumentRoot to the application's public directory and allow the rewrite behavior the framework expects.

Do not test PHP with a permanent phpinfo page

A temporary file containing <?php phpinfo(); is useful for confirming Apache's PHP integration, but remove it immediately after testing. The output reveals loaded modules, filesystem paths, server configuration, and environment details that are useful for debugging and equally useful to an attacker.

MySQL root authentication may not work the way older tutorials expect

Ubuntu's packaged MySQL commonly configures local administrative access around the operating-system account rather than requiring the same password-based root flow shown in older generic guides. If mysql -u root -p behaves differently than expected, inspect the installed authentication configuration before resetting credentials. For applications, create a dedicated database and a least-privileged application user instead of connecting Laravel or plain PHP as MySQL root.

Topics: Deployment & Hosting