What Is LAMP Stack and When Do You Need It?
If you’re just getting started with backend web development or you’ve been handed a task to deploy a PHP application to a server, chances are you’ll need LAMP Stack. It’s the classic combination of Linux + Apache + MySQL + PHP — the foundation that powers WordPress, Laravel, Drupal, and hundreds of other PHP applications. Apache alone holds around 30% of the global web server market share, so knowing how to set up LAMP is a genuinely practical skill.
I’ve used LAMP on our company’s staging environment (Ubuntu 22.04) to test configurations before pushing to production. The hard-learned lesson: install in the right order and configure correctly from the start. Do it backwards and you’ll spend an entire afternoon debugging things that never should have been a problem.
This guide uses Apache instead of Nginx because many legacy PHP projects still depend on mod_rewrite and .htaccess. If you’re looking for a Nginx setup, there’s a separate post on the blog for that.
Installing Each Component
1. Update the System
Before installing anything, always update the package list — skipping this step is a common source of version conflicts down the road:
sudo apt update && sudo apt upgrade -y
2. Install Apache
sudo apt install apache2 -y
Once that’s done, start the service and enable it to run on boot:
sudo systemctl start apache2
sudo systemctl enable apache2
If you’re using UFW, open port 80:
sudo ufw allow 'Apache'
sudo ufw reload
Navigate to http://<your-server-IP> in a browser. If you see the “Apache2 Ubuntu Default Page”, you’re good to go.
3. Install MySQL
sudo apt install mysql-server -y
Run the security script — this step is important, don’t skip it:
sudo mysql_secure_installation
The script will walk you through a series of prompts. For production environments, here’s how I always answer:
- VALIDATE PASSWORD component: Y (enable password strength checking)
- Remove anonymous users: Y
- Disallow root login remotely: Y
- Remove test database: Y
- Reload privilege tables: Y
Log in to MySQL to confirm everything is working:
sudo mysql -u root -p
4. Install PHP
Ubuntu 22.04 ships PHP 8.1 in its default repositories. Install it along with the commonly needed extensions:
sudo apt install php libapache2-mod-php php-mysql php-cli php-curl php-gd php-mbstring php-xml php-zip -y
Here’s a quick breakdown of why each extension matters:
php-mysql— connects PHP to MySQL/MariaDBphp-mbstring— handles multibyte string processing (required for Japanese, Vietnamese, etc.)php-xml— handles XML parsing; many PHP frameworks won’t run without thisphp-zip— used by WordPress when installing or updating plugins
Verify the installed version:
php -v
Detailed Configuration
Creating a Virtual Host for Your Application
Dropping everything into the default /var/www/html directory is fine for a quick test, but no more than that. I always create a dedicated Virtual Host for each project — it lets you run multiple websites on the same server without them interfering with each other.
Create the project directory and set ownership:
sudo mkdir -p /var/www/myapp/public
sudo chown -R $USER:$USER /var/www/myapp/public
sudo chmod -R 755 /var/www/myapp
Open a new Virtual Host config file:
sudo nano /etc/apache2/sites-available/myapp.conf
Paste in the following:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName myapp.local
DocumentRoot /var/www/myapp/public
<Directory /var/www/myapp/public>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>
Enable the site and the mod_rewrite module — both Laravel and WordPress require it:
sudo a2ensite myapp.conf
sudo a2enmod rewrite
sudo systemctl restart apache2
Creating a MySQL Database and User for Your Application
Never connect to your database as root from your application — always create a dedicated user with the minimum necessary privileges:
sudo mysql -u root -p
CREATE DATABASE myapp_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Note: Use utf8mb4 instead of utf8 to ensure full Unicode support, including emoji. WordPress had a well-known bug where emoji would get corrupted on save — all because the utf8 charset only supports 3 bytes per character, while emoji require 4.
Tuning PHP Configuration for Production
The PHP config file for Apache lives at /etc/php/8.1/apache2/php.ini. These are the settings I adjust immediately after a fresh install:
sudo nano /etc/php/8.1/apache2/php.ini
Use Ctrl+W in nano to search for each setting, then update them as follows:
; File upload size limit (adjust to your needs)
upload_max_filesize = 64M
post_max_size = 64M
; Increase memory limit for heavier applications
memory_limit = 256M
; Maximum script execution time (seconds)
max_execution_time = 60
; Disable error display on production (enable during development)
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
Save the file, then restart Apache to apply the changes:
sudo systemctl restart apache2
Testing and Monitoring
Verify PHP Is Working Correctly
Create a phpinfo.php file to test:
sudo nano /var/www/myapp/public/phpinfo.php
<?php
phpinfo();
?>
Visit http://<your-server-IP>/phpinfo.php — you’ll see the full PHP information page. Check that the extensions you installed (mysql, mbstring, xml, etc.) are listed.
Delete this file immediately after you’re done — leaving it publicly accessible is a serious security vulnerability. It exposes your entire server configuration to anyone who visits the URL:
sudo rm /var/www/myapp/public/phpinfo.php
Test the PHP → MySQL Connection
Create a database connection test file:
<?php
$conn = new mysqli('localhost', 'myapp_user', 'StrongPassword123!', 'myapp_db');
if ($conn->connect_error) {
die('Connection error: ' . $conn->connect_error);
}
echo 'MySQL connection successful! Server version: ' . $conn->server_info;
$conn->close();
?>
If you see “MySQL connection successful”, your LAMP Stack is working end-to-end. Remember to delete this test file once you’ve confirmed everything is working.
Three Service Check Commands Worth Bookmarking
Before announcing “deployment complete” to the team, I always do a quick run through these:
# Check Apache status
sudo systemctl status apache2
# Check MySQL status
sudo systemctl status mysql
# Watch Apache error log in real time
sudo tail -f /var/log/apache2/error.log
# Watch MySQL error log
sudo tail -f /var/log/mysql/error.log
Or use this cleaner one-liner:
for svc in apache2 mysql; do
echo -n "$svc: "
systemctl is-active $svc
done
Both should print active.
Check Which Ports Are Listening
sudo ss -tlnp | grep -E '(:80|:443|:3306)'
Apache should be on port 80, MySQL on 3306. Note that MySQL only binds to 127.0.0.1 by default — this is the correct secure configuration and means it’s not exposed to the internet.
Common Issues and Fixes
- Apache won’t start: Run
sudo apachectl configtestfirst. The most common culprit is a config syntax error — a missing bracket or angle bracket — or port 80 already being in use by another process. - PHP extension won’t load: Check
/etc/php/8.1/apache2/conf.d/— each extension has its own.inifile there. Quickly verify withphp -m | grep mysql. - MySQL refuses connection: This is a common gotcha —
'user'@'localhost'and'user'@'127.0.0.1'are treated as two different users in MySQL. Double-check the host you specified when creating the user.

