LAMP Stack Installation (Linux, Apache, MySQL, PHP): Complete Production Guide
Introduction
The LAMP stack (Linux, Apache, MySQL, PHP) is one of the most popular and battle-tested web development platforms for hosting dynamic websites and web applications. This open-source software bundle has powered millions of websites worldwide, from small blogs to enterprise applications. The LAMP stack provides a robust, flexible, and cost-effective solution for web hosting that combines the stability of Linux, the reliability of Apache, the power of MySQL/MariaDB, and the versatility of PHP.
In this comprehensive guide, you'll learn how to install and configure a production-ready LAMP stack on Linux servers (Ubuntu/Debian and CentOS/Rocky Linux). We'll cover security hardening, performance optimization, best practices, and troubleshooting to ensure your web applications run efficiently and securely.
What You'll Learn
- Complete LAMP stack installation on Ubuntu/Debian and CentOS/Rocky Linux
- Apache web server configuration and virtual host setup
- MySQL/MariaDB installation, security configuration, and optimization
- PHP installation with multiple version support
- Security hardening techniques and SSL/TLS certificate configuration
- Performance tuning and optimization strategies
- Monitoring and troubleshooting common issues
- Production-ready configurations and best practices
Why Choose LAMP Stack?
The LAMP stack offers several compelling advantages:
- Mature and Stable: Decades of development and testing
- Extensive Community Support: Large community with abundant resources
- Cost-Effective: All components are free and open-source
- Flexibility: Easily customizable for various use cases
- Wide Compatibility: Supports most PHP applications including WordPress, Drupal, Magento
- Well-Documented: Extensive documentation and tutorials available
- Enterprise-Ready: Used by major organizations worldwide
Prerequisites
Before beginning the LAMP stack installation, ensure you have:
System Requirements
- Operating System: Ubuntu 20.04/22.04 LTS, Debian 10/11, CentOS 7/8, or Rocky Linux 8/9
- RAM: Minimum 1GB (2GB+ recommended for production)
- Disk Space: At least 10GB free space (20GB+ recommended)
- CPU: 1+ cores (2+ cores recommended for production)
- Network: Active internet connection for package downloads
Access Requirements
- Root or sudo access to the server
- SSH access to the server
- Basic knowledge of Linux command line
- Understanding of networking concepts (IP addresses, DNS, ports)
Pre-Installation Checklist
- Update system packages to latest versions
- Configure firewall rules to allow HTTP (80) and HTTPS (443)
- Set up DNS records pointing to your server
- Prepare domain names for virtual hosts
- Plan your directory structure for web applications
Installation
Step 1: System Update and Preparation
First, update your system packages to ensure you have the latest security patches and software versions.
For Ubuntu/Debian:
# Update package repository cache
sudo apt update
# Upgrade all installed packages
sudo apt upgrade -y
# Install essential utilities
sudo apt install -y curl wget vim git unzip software-properties-common
For CentOS/Rocky Linux:
# Update package repository cache
sudo dnf update -y
# Install EPEL repository (Extra Packages for Enterprise Linux)
sudo dnf install -y epel-release
# Install essential utilities
sudo dnf install -y curl wget vim git unzip
Step 2: Apache Web Server Installation
Apache HTTP Server is the A in LAMP, providing the web serving capabilities.
Ubuntu/Debian Installation:
# Install Apache web server
sudo apt install -y apache2
# Enable Apache to start on boot
sudo systemctl enable apache2
# Start Apache service
sudo systemctl start apache2
# Verify Apache is running
sudo systemctl status apache2
CentOS/Rocky Linux Installation:
# Install Apache (httpd package)
sudo dnf install -y httpd
# Enable Apache to start on boot
sudo systemctl enable httpd
# Start Apache service
sudo systemctl start httpd
# Verify Apache is running
sudo systemctl status httpd
Configure Firewall for Apache:
Ubuntu/Debian (UFW):
# Allow Apache through firewall
sudo ufw allow 'Apache Full'
# Verify firewall rules
sudo ufw status
CentOS/Rocky Linux (firewalld):
# Allow HTTP traffic
sudo firewall-cmd --permanent --add-service=http
# Allow HTTPS traffic
sudo firewall-cmd --permanent --add-service=https
# Reload firewall rules
sudo firewall-cmd --reload
# Verify firewall rules
sudo firewall-cmd --list-all
Verify Apache Installation:
Open your web browser and navigate to your server's IP address:
http://your_server_ip
You should see the Apache default welcome page.
Step 3: MySQL/MariaDB Installation
MySQL (or MariaDB) provides the database management system for the LAMP stack.
Ubuntu/Debian Installation:
# Install MariaDB server (recommended over MySQL)
sudo apt install -y mariadb-server mariadb-client
# Enable MariaDB to start on boot
sudo systemctl enable mariadb
# Start MariaDB service
sudo systemctl start mariadb
# Verify MariaDB is running
sudo systemctl status mariadb
CentOS/Rocky Linux Installation:
# Install MariaDB server
sudo dnf install -y mariadb-server mariadb
# Enable MariaDB to start on boot
sudo systemctl enable mariadb
# Start MariaDB service
sudo systemctl start mariadb
# Verify MariaDB is running
sudo systemctl status mariadb
Secure MySQL/MariaDB Installation:
Run the security script to remove default insecure settings:
sudo mysql_secure_installation
Follow the prompts:
- Set root password: Choose a strong password
- Remove anonymous users: Yes
- Disallow root login remotely: Yes (for security)
- Remove test database: Yes
- Reload privilege tables: Yes
Test MySQL/MariaDB Connection:
# Login to MySQL as root
sudo mysql -u root -p
# Once logged in, check version
SELECT VERSION();
# Exit MySQL
EXIT;
Step 4: PHP Installation
PHP is the scripting language that processes dynamic content in the LAMP stack.
Ubuntu/Debian Installation:
# Install PHP and common modules
sudo apt install -y php libapache2-mod-php php-mysql php-cli php-curl php-gd php-mbstring php-xml php-xmlrpc php-zip php-intl php-bcmath php-json php-soap
# Restart Apache to load PHP module
sudo systemctl restart apache2
# Verify PHP version
php -v
CentOS/Rocky Linux Installation:
# Install PHP and common modules
sudo dnf install -y php php-mysqlnd php-cli php-curl php-gd php-mbstring php-xml php-xmlrpc php-zip php-intl php-bcmath php-json php-soap
# Restart Apache to load PHP module
sudo systemctl restart httpd
# Verify PHP version
php -v
Test PHP Installation:
Create a PHP info file to verify PHP is working:
# Create PHP info file
sudo bash -c 'cat > /var/www/html/info.php <<EOF
<?php
phpinfo();
?>
EOF'
# Set proper permissions
sudo chmod 644 /var/www/html/info.php
Access the PHP info page in your browser:
http://your_server_ip/info.php
You should see detailed PHP configuration information.
Important: Remove the info.php file after verification for security:
sudo rm /var/www/html/info.php
Step 5: Verify LAMP Stack Installation
Create a simple PHP script that connects to MySQL to verify all components work together:
sudo bash -c 'cat > /var/www/html/test_db.php <<EOF
<?php
\$servername = "localhost";
\$username = "root";
\$password = "your_mysql_root_password";
// Create connection
\$conn = new mysqli(\$servername, \$username, \$password);
// Check connection
if (\$conn->connect_error) {
die("Connection failed: " . \$conn->connect_error);
}
echo "LAMP Stack is working! PHP successfully connected to MySQL.";
\$conn->close();
?>
EOF'
Access the test script:
http://your_server_ip/test_db.php
Important: Delete this test file after verification:
sudo rm /var/www/html/test_db.php
Configuration
Apache Configuration
Main Configuration Files:
- Ubuntu/Debian:
/etc/apache2/apache2.conf - CentOS/Rocky:
/etc/httpd/conf/httpd.conf
Configure Apache Virtual Hosts:
Virtual hosts allow you to host multiple websites on a single server.
Ubuntu/Debian Virtual Host:
# Create directory for your website
sudo mkdir -p /var/www/example.com/public_html
# Set ownership
sudo chown -R $USER:$USER /var/www/example.com/public_html
# Set permissions
sudo chmod -R 755 /var/www/example.com
# Create sample index page
cat > /var/www/example.com/public_html/index.html <<EOF
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Example.com</title>
</head>
<body>
<h1>Success! The example.com virtual host is working!</h1>
</body>
</html>
EOF
# Create virtual host configuration
sudo bash -c 'cat > /etc/apache2/sites-available/example.com.conf <<EOF
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
ServerAdmin [email protected]
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog \${APACHE_LOG_DIR}/example.com-error.log
CustomLog \${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
EOF'
# Enable the virtual host
sudo a2ensite example.com.conf
# Enable mod_rewrite (for URL rewriting)
sudo a2enmod rewrite
# Test Apache configuration
sudo apache2ctl configtest
# Restart Apache
sudo systemctl restart apache2
CentOS/Rocky Virtual Host:
# Create directory for your website
sudo mkdir -p /var/www/example.com/public_html
# Set ownership
sudo chown -R apache:apache /var/www/example.com/public_html
# Set permissions
sudo chmod -R 755 /var/www/example.com
# Create sample index page
sudo bash -c 'cat > /var/www/example.com/public_html/index.html <<EOF
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Example.com</title>
</head>
<body>
<h1>Success! The example.com virtual host is working!</h1>
</body>
</html>
EOF'
# Create virtual host configuration
sudo bash -c 'cat > /etc/httpd/conf.d/example.com.conf <<EOF
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
ServerAdmin [email protected]
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog /var/log/httpd/example.com-error.log
CustomLog /var/log/httpd/example.com-access.log combined
</VirtualHost>
EOF'
# Test Apache configuration
sudo httpd -t
# Restart Apache
sudo systemctl restart httpd
Apache Performance Tuning:
Edit the MPM (Multi-Processing Module) configuration:
Ubuntu/Debian:
sudo vim /etc/apache2/mods-available/mpm_prefork.conf
CentOS/Rocky:
sudo vim /etc/httpd/conf.modules.d/00-mpm.conf
Recommended MPM Prefork settings for a server with 2GB RAM:
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 150
MaxConnectionsPerChild 3000
</IfModule>
MySQL/MariaDB Configuration
Main Configuration File:
- Ubuntu/Debian:
/etc/mysql/mariadb.conf.d/50-server.cnf - CentOS/Rocky:
/etc/my.cnf.d/mariadb-server.cnf
Create Database and User:
# Login to MySQL
sudo mysql -u root -p
# Create database
CREATE DATABASE myapp_db;
# Create user with password
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'strong_password_here';
# Grant privileges
GRANT ALL PRIVILEGES ON myapp_db.* TO 'myapp_user'@'localhost';
# Flush privileges
FLUSH PRIVILEGES;
# Exit
EXIT;
MySQL Performance Tuning:
Edit MySQL configuration file and add these optimizations:
[mysqld]
# Basic settings
max_connections = 100
connect_timeout = 10
wait_timeout = 600
max_allowed_packet = 64M
thread_cache_size = 128
sort_buffer_size = 4M
bulk_insert_buffer_size = 16M
tmp_table_size = 32M
max_heap_table_size = 32M
# InnoDB settings (for 2GB RAM server)
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table = 1
# Query cache (deprecated in newer versions)
query_cache_limit = 2M
query_cache_size = 64M
# Logging
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2
Restart MySQL to apply changes:
sudo systemctl restart mariadb
PHP Configuration
Main Configuration File:
- Ubuntu/Debian:
/etc/php/8.x/apache2/php.ini - CentOS/Rocky:
/etc/php.ini
Recommended PHP Settings:
Edit the php.ini file and adjust these settings:
# Memory and execution limits
memory_limit = 256M
max_execution_time = 300
max_input_time = 300
post_max_size = 64M
upload_max_filesize = 64M
# Error reporting (for production)
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors = On
error_log = /var/log/php_errors.log
# Security settings
expose_php = Off
allow_url_fopen = On
allow_url_include = Off
# Session settings
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
# Timezone
date.timezone = America/New_York
# OPcache settings (performance)
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
Restart Apache to apply PHP changes:
# Ubuntu/Debian
sudo systemctl restart apache2
# CentOS/Rocky
sudo systemctl restart httpd
Deployment
Deploying a PHP Application
Method 1: Manual Deployment
# Create application directory
sudo mkdir -p /var/www/myapp.com/public_html
# Upload your application files using SCP
scp -r /path/to/local/app/* user@server_ip:/var/www/myapp.com/public_html/
# Or use rsync for incremental updates
rsync -avz --progress /path/to/local/app/ user@server_ip:/var/www/myapp.com/public_html/
# Set proper ownership
sudo chown -R www-data:www-data /var/www/myapp.com/public_html # Ubuntu/Debian
sudo chown -R apache:apache /var/www/myapp.com/public_html # CentOS/Rocky
# Set proper permissions
sudo find /var/www/myapp.com/public_html -type d -exec chmod 755 {} \;
sudo find /var/www/myapp.com/public_html -type f -exec chmod 644 {} \;
Method 2: Git-Based Deployment
# Install git if not already installed
sudo apt install git -y # Ubuntu/Debian
sudo dnf install git -y # CentOS/Rocky
# Clone repository
cd /var/www/myapp.com
sudo git clone https://github.com/username/myapp.git public_html
# Set proper ownership
sudo chown -R www-data:www-data /var/www/myapp.com/public_html # Ubuntu/Debian
# Configure automatic updates (optional)
cd /var/www/myapp.com/public_html
sudo git config --global --add safe.directory /var/www/myapp.com/public_html
Deploy WordPress Example:
# Download WordPress
cd /tmp
wget https://wordpress.org/latest.tar.gz
# Extract WordPress
tar -xzf latest.tar.gz
# Move to web directory
sudo mv wordpress/* /var/www/myapp.com/public_html/
# Create wp-config.php
sudo cp /var/www/myapp.com/public_html/wp-config-sample.php /var/www/myapp.com/public_html/wp-config.php
# Edit wp-config.php with database credentials
sudo vim /var/www/myapp.com/public_html/wp-config.php
# Set proper ownership
sudo chown -R www-data:www-data /var/www/myapp.com/public_html
# Set proper permissions
sudo find /var/www/myapp.com/public_html -type d -exec chmod 755 {} \;
sudo find /var/www/myapp.com/public_html -type f -exec chmod 644 {} \;
SSL/TLS Certificate Installation
Secure your site with Let's Encrypt free SSL certificates:
Ubuntu/Debian:
# Install Certbot
sudo apt install -y certbot python3-certbot-apache
# Obtain and install certificate
sudo certbot --apache -d example.com -d www.example.com
# Test automatic renewal
sudo certbot renew --dry-run
CentOS/Rocky:
# Install Certbot
sudo dnf install -y certbot python3-certbot-apache
# Obtain and install certificate
sudo certbot --apache -d example.com -d www.example.com
# Test automatic renewal
sudo certbot renew --dry-run
Certbot will automatically configure Apache for HTTPS and set up automatic renewal.
Monitoring
Apache Monitoring
Enable Apache Status Module:
Ubuntu/Debian:
# Enable status module
sudo a2enmod status
# Restart Apache
sudo systemctl restart apache2
CentOS/Rocky:
# Add to Apache configuration
sudo bash -c 'cat >> /etc/httpd/conf.d/status.conf <<EOF
<Location "/server-status">
SetHandler server-status
Require local
</Location>
EOF'
# Restart Apache
sudo systemctl restart httpd
Access server status:
http://localhost/server-status
Monitor Apache Logs:
# Real-time access log monitoring
sudo tail -f /var/log/apache2/access.log # Ubuntu/Debian
sudo tail -f /var/log/httpd/access_log # CentOS/Rocky
# Real-time error log monitoring
sudo tail -f /var/log/apache2/error.log # Ubuntu/Debian
sudo tail -f /var/log/httpd/error_log # CentOS/Rocky
# Analyze most requested URLs
awk '{print $7}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
# Analyze HTTP status codes
awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -rn
# Analyze top visitor IPs
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
MySQL/MariaDB Monitoring
Monitor Database Performance:
# Login to MySQL
sudo mysql -u root -p
# Show current processes
SHOW PROCESSLIST;
# Show database status
SHOW STATUS;
# Show InnoDB status
SHOW ENGINE INNODB STATUS\G
# Show slow queries
SHOW VARIABLES LIKE 'slow_query_log%';
# Monitor database connections
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Max_used_connections';
Monitor MySQL Logs:
# View MySQL error log
sudo tail -f /var/log/mysql/error.log
# View slow query log
sudo tail -f /var/log/mysql/slow-query.log
# Analyze slow queries with mysqldumpslow
sudo mysqldumpslow -s t -t 10 /var/log/mysql/slow-query.log
PHP Monitoring
Monitor PHP Errors:
# View PHP error log
sudo tail -f /var/log/php_errors.log
# Monitor PHP-FPM status (if using PHP-FPM)
sudo systemctl status php7.4-fpm # Ubuntu/Debian
sudo systemctl status php-fpm # CentOS/Rocky
Check PHP OPcache Status:
Create a simple status script:
sudo bash -c 'cat > /var/www/html/opcache-status.php <<EOF
<?php
if (function_exists("opcache_get_status")) {
\$status = opcache_get_status();
echo "<pre>";
print_r(\$status);
echo "</pre>";
} else {
echo "OPcache is not enabled";
}
?>
EOF'
Access: http://your_server_ip/opcache-status.php
Remember to delete this file after checking:
sudo rm /var/www/html/opcache-status.php
System Resource Monitoring
# Monitor CPU and memory usage
htop
# Monitor disk usage
df -h
# Monitor disk I/O
iostat -x 1
# Monitor network connections
netstat -tunlp
# Monitor Apache connections
netstat -an | grep :80 | wc -l
# Monitor MySQL connections
netstat -an | grep :3306 | wc -l
Automated Monitoring Script
Create a monitoring script:
sudo bash -c 'cat > /usr/local/bin/lamp-monitor.sh <<EOF
#!/bin/bash
echo "=== LAMP Stack Monitoring Report ==="
echo "Date: \$(date)"
echo ""
echo "=== Apache Status ==="
systemctl status apache2 | head -3 || systemctl status httpd | head -3
echo "Active connections: \$(netstat -an | grep :80 | wc -l)"
echo ""
echo "=== MySQL Status ==="
systemctl status mariadb | head -3
echo "Active connections: \$(netstat -an | grep :3306 | wc -l)"
echo ""
echo "=== Disk Usage ==="
df -h | grep -E "Filesystem|/dev/|/var"
echo ""
echo "=== Memory Usage ==="
free -h
echo ""
echo "=== Top Processes by CPU ==="
ps aux --sort=-%cpu | head -6
echo ""
echo "=== Top Processes by Memory ==="
ps aux --sort=-%mem | head -6
EOF'
# Make executable
sudo chmod +x /usr/local/bin/lamp-monitor.sh
# Run the script
sudo /usr/local/bin/lamp-monitor.sh
Troubleshooting
Apache Not Starting
Issue: Apache fails to start
Check error logs:
# Ubuntu/Debian
sudo journalctl -u apache2 -n 50
sudo tail -n 50 /var/log/apache2/error.log
# CentOS/Rocky
sudo journalctl -u httpd -n 50
sudo tail -n 50 /var/log/httpd/error_log
Common solutions:
- Port already in use:
# Check what's using port 80
sudo lsof -i :80
sudo netstat -tunlp | grep :80
# Kill the conflicting process or change Apache port
- Configuration syntax error:
# Test configuration
sudo apache2ctl configtest # Ubuntu/Debian
sudo httpd -t # CentOS/Rocky
# Fix syntax errors shown in output
- Missing SSL certificate:
# If SSL certificate is missing, temporarily disable SSL virtual host
sudo a2dissite example.com-ssl.conf # Ubuntu/Debian
# Or comment out SSL virtual host in CentOS/Rocky
MySQL Connection Errors
Issue: "Can't connect to MySQL server"
Solutions:
- Check if MySQL is running:
sudo systemctl status mariadb
sudo systemctl start mariadb
- Check MySQL socket file:
# Find socket file location
mysql_config --socket
# Verify socket file exists
ls -l /var/run/mysqld/mysqld.sock
# If missing, restart MySQL
sudo systemctl restart mariadb
- Check firewall and bind-address:
# Edit MySQL configuration
sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf
# Ensure bind-address is set correctly
bind-address = 127.0.0.1 # For local connections only
# or
bind-address = 0.0.0.0 # For remote connections (less secure)
# Restart MySQL
sudo systemctl restart mariadb
- Verify user credentials:
# Login to MySQL
sudo mysql -u root -p
# Check user exists
SELECT User, Host FROM mysql.user;
# Grant proper privileges
GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'localhost';
FLUSH PRIVILEGES;
PHP Not Executing
Issue: PHP files download instead of executing
Solutions:
- Verify PHP module is loaded:
# Ubuntu/Debian
apache2ctl -M | grep php
# CentOS/Rocky
httpd -M | grep php
# If not loaded, enable PHP module
sudo a2enmod php7.4 # Ubuntu/Debian
# Restart Apache
sudo systemctl restart apache2 # Ubuntu/Debian
sudo systemctl restart httpd # CentOS/Rocky
- Check Apache configuration:
# Ensure DirectoryIndex includes PHP files
# Add to Apache configuration or .htaccess:
DirectoryIndex index.php index.html
# Add PHP handler
AddHandler application/x-httpd-php .php
- Verify PHP installation:
php -v
php -m # List PHP modules
Permission Errors
Issue: "403 Forbidden" or permission denied errors
Solutions:
- Set proper ownership:
# Ubuntu/Debian
sudo chown -R www-data:www-data /var/www/your_site
# CentOS/Rocky
sudo chown -R apache:apache /var/www/your_site
- Set proper permissions:
# Directories: 755
sudo find /var/www/your_site -type d -exec chmod 755 {} \;
# Files: 644
sudo find /var/www/your_site -type f -exec chmod 644 {} \;
# Writable directories (uploads, cache): 775
sudo chmod 775 /var/www/your_site/uploads
- Check SELinux (CentOS/Rocky):
# Check SELinux status
getenforce
# Set correct SELinux context
sudo chcon -R -t httpd_sys_content_t /var/www/your_site
sudo chcon -R -t httpd_sys_rw_content_t /var/www/your_site/uploads
# Or disable SELinux temporarily for testing
sudo setenforce 0
# To make permanent, edit /etc/selinux/config
High Memory Usage
Issue: Server running out of memory
Solutions:
- Optimize Apache MPM settings:
# Reduce MaxRequestWorkers in MPM configuration
# See Apache Performance Tuning section above
- Optimize MySQL memory usage:
# Reduce buffer pool size in MySQL configuration
innodb_buffer_pool_size = 256M # Instead of 512M
# Restart MySQL
sudo systemctl restart mariadb
- Enable PHP OPcache:
# Verify OPcache is enabled in php.ini
opcache.enable = 1
opcache.memory_consumption = 128
# Restart Apache
sudo systemctl restart apache2 # Ubuntu/Debian
sudo systemctl restart httpd # CentOS/Rocky
- Monitor and kill high-memory processes:
# Find memory-hungry processes
ps aux --sort=-%mem | head -10
# Kill specific process if necessary
sudo kill -9 PID
Slow Website Performance
Issue: Website loads slowly
Diagnostic steps:
- Check server load:
uptime
top
htop
- Analyze Apache access logs:
# Find slow requests
awk '$NF > 1000 {print $0}' /var/log/apache2/access.log | tail -20
- Identify slow MySQL queries:
# Enable slow query log
sudo mysql -u root -p
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
# Check slow query log
sudo tail -f /var/log/mysql/slow-query.log
- Check PHP execution time:
# Add to PHP script for debugging
ini_set('display_errors', 1);
error_reporting(E_ALL);
$start = microtime(true);
// Your code here
$end = microtime(true);
echo "Execution time: " . ($end - $start) . " seconds";
Performance optimization:
- Enable caching (see Performance Tuning section)
- Optimize database queries and add indexes
- Enable compression (Gzip/Brotli)
- Use a CDN for static content
- Optimize images and assets
- Implement PHP OPcache
- Use Redis or Memcached for session storage
Security Best Practices
Apache Security Hardening
- Hide Apache version information:
# Edit Apache configuration
sudo vim /etc/apache2/conf-available/security.conf # Ubuntu/Debian
sudo vim /etc/httpd/conf/httpd.conf # CentOS/Rocky
# Add or modify these lines
ServerTokens Prod
ServerSignature Off
- Disable directory listing:
# In virtual host configuration
Options -Indexes +FollowSymLinks
- Restrict access by IP (if needed):
<Directory /var/www/admin>
Require ip 192.168.1.0/24
Require ip 10.0.0.5
</Directory>
- Enable ModSecurity (Web Application Firewall):
# Ubuntu/Debian
sudo apt install -y libapache2-mod-security2
# Enable module
sudo a2enmod security2
# Restart Apache
sudo systemctl restart apache2
MySQL Security Hardening
- Disable remote root login:
sudo mysql -u root -p
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
FLUSH PRIVILEGES;
- Use strong passwords:
# Set password policy
SET GLOBAL validate_password.policy = STRONG;
SET GLOBAL validate_password.length = 12;
- Regular backups:
# Create backup script
sudo bash -c 'cat > /usr/local/bin/mysql-backup.sh <<EOF
#!/bin/bash
DATE=\$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backup/mysql"
mkdir -p \$BACKUP_DIR
mysqldump -u root -p\$MYSQL_ROOT_PASSWORD --all-databases | gzip > \$BACKUP_DIR/all_databases_\$DATE.sql.gz
find \$BACKUP_DIR -type f -mtime +7 -delete
EOF'
sudo chmod +x /usr/local/bin/mysql-backup.sh
- Limit database user privileges:
# Grant only necessary privileges
GRANT SELECT, INSERT, UPDATE, DELETE ON database_name.* TO 'user'@'localhost';
# Avoid using GRANT ALL unless necessary
PHP Security Hardening
- Disable dangerous functions:
# Add to php.ini
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
- Configure file upload security:
# Add to php.ini
file_uploads = On
upload_max_filesize = 10M
max_file_uploads = 5
# In your PHP application, validate file types
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($_FILES['file']['type'], $allowed_types)) {
die('Invalid file type');
}
- Use prepared statements for database queries:
// Bad (vulnerable to SQL injection)
$query = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";
// Good (using prepared statements)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $_POST['username']]);
- Enable open_basedir restriction:
# Add to php.ini or virtual host configuration
open_basedir = /var/www/your_site:/tmp
Firewall Configuration
- Configure UFW (Ubuntu/Debian):
# Enable firewall
sudo ufw enable
# Allow SSH
sudo ufw allow 22/tcp
# Allow HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow MySQL only from specific IP (if needed)
sudo ufw allow from 192.168.1.100 to any port 3306
# View rules
sudo ufw status verbose
- Configure firewalld (CentOS/Rocky):
# Enable firewall
sudo systemctl enable firewalld
sudo systemctl start firewalld
# Allow HTTP and HTTPS
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Allow MySQL only from specific IP (if needed)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port port="3306" protocol="tcp" accept'
# Reload firewall
sudo firewall-cmd --reload
# View rules
sudo firewall-cmd --list-all
Fail2Ban for Brute Force Protection
# Install Fail2Ban
sudo apt install -y fail2ban # Ubuntu/Debian
sudo dnf install -y fail2ban # CentOS/Rocky
# Create local configuration
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Edit configuration
sudo vim /etc/fail2ban/jail.local
# Add Apache protection
[apache-auth]
enabled = true
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 3
bantime = 3600
# Enable and start Fail2Ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status
Performance Optimization
Enable Apache Caching
- Enable mod_cache:
# Ubuntu/Debian
sudo a2enmod cache
sudo a2enmod cache_disk
sudo a2enmod expires
sudo a2enmod headers
# Restart Apache
sudo systemctl restart apache2
- Configure caching in virtual host:
<VirtualHost *:80>
# ... other configuration ...
# Enable caching
CacheEnable disk /
CacheRoot /var/cache/apache2/mod_cache_disk
CacheDefaultExpire 3600
CacheMaxExpire 86400
# Browser caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType text/html "access plus 1 hour"
</IfModule>
</VirtualHost>
Enable Gzip Compression
# Ubuntu/Debian
sudo a2enmod deflate
# Add to virtual host or .htaccess
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>
# Restart Apache
sudo systemctl restart apache2
MySQL Query Optimization
- Enable query cache:
# Add to MySQL configuration
query_cache_type = 1
query_cache_size = 64M
query_cache_limit = 2M
- Add indexes to frequently queried columns:
# Analyze slow queries
EXPLAIN SELECT * FROM table WHERE column = 'value';
# Add index if needed
CREATE INDEX idx_column ON table(column);
# View existing indexes
SHOW INDEX FROM table;
- Optimize tables regularly:
# Run optimization
sudo mysql -u root -p
OPTIMIZE TABLE table_name;
# Or optimize all tables in a database
mysqlcheck -u root -p --optimize database_name
PHP OPcache Configuration
OPcache caches compiled PHP code in memory, significantly improving performance:
# Verify OPcache is enabled
php -i | grep opcache
# Recommended OPcache settings in php.ini
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.enable_cli=0
# Restart Apache
sudo systemctl restart apache2 # Ubuntu/Debian
sudo systemctl restart httpd # CentOS/Rocky
Use Redis for Session Storage
Installing Redis for PHP session storage improves performance:
# Install Redis
sudo apt install -y redis-server php-redis # Ubuntu/Debian
sudo dnf install -y redis php-redis # CentOS/Rocky
# Configure PHP to use Redis for sessions
sudo vim /etc/php/8.x/apache2/php.ini
# Add these lines
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"
# Restart services
sudo systemctl restart redis
sudo systemctl restart apache2 # Ubuntu/Debian
sudo systemctl restart httpd # CentOS/Rocky
Conclusion
You now have a fully functional, production-ready LAMP stack configured with security hardening, performance optimizations, and monitoring tools. This comprehensive setup provides a solid foundation for hosting PHP-based web applications ranging from simple websites to complex web platforms.
Key Takeaways
- Security First: Always implement security best practices including SSL/TLS, strong passwords, firewall rules, and regular updates
- Performance Matters: Enable caching, compression, and optimize database queries for better performance
- Regular Monitoring: Set up monitoring tools and review logs regularly to catch issues early
- Backup Everything: Implement automated backup strategies for both files and databases
- Keep Updated: Regularly update all components (Linux, Apache, MySQL, PHP) for security patches
- Documentation: Document your configuration and customizations for future reference
Next Steps
- Implement Automated Backups: Set up daily automated backups of your databases and web files
- Configure Monitoring: Install monitoring tools like Nagios, Zabbix, or use cloud-based solutions
- Set Up Staging Environment: Create a staging environment to test changes before production
- Implement CI/CD: Automate deployment with tools like Jenkins, GitLab CI, or GitHub Actions
- Consider High Availability: For critical applications, implement load balancing and database replication
- Performance Testing: Regularly perform load testing to identify bottlenecks
- Security Audits: Conduct regular security audits and vulnerability scans
Additional Resources
- Apache Documentation: https://httpd.apache.org/docs/
- MySQL Documentation: https://dev.mysql.com/doc/
- MariaDB Documentation: https://mariadb.org/documentation/
- PHP Documentation: https://www.php.net/docs.php
- Let's Encrypt: https://letsencrypt.org/docs/
- DigitalOcean Tutorials: https://www.digitalocean.com/community/tutorials
- Linux Academy: https://linuxacademy.com/
Support and Community
If you encounter issues or need help:
- Stack Overflow: Search or ask questions about specific problems
- Server Fault: For system administration questions
- Apache Users Mailing List: For Apache-specific issues
- MySQL Forums: For database-related questions
- PHP Community: PHP.net and various PHP forums
The LAMP stack remains one of the most reliable and widely-adopted web hosting solutions. With proper configuration, security measures, and ongoing maintenance, your LAMP stack will provide years of reliable service for your web applications.
Happy deploying!


