Back to blog

Web Server

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning

Full LAMP installation and optimization: MPM worker tuning, MySQL InnoDB settings, PHP-FPM pools, and .htaccess security hardening.

  • LAMP
  • Ubuntu
  • Apache
  • MySQL
  • PHP-FPM
  • Web Server

Reader map

Key points in How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning

Syntax first, runtime behavior second, migration cleanup last.

Read
17 min
Waypoints
8
Track
Web Server
  1. 01
    Start here

    Apache should serve static files and pass PHP to PHP-FPM.

  2. 02
    Waypoint

    Use mpm_event or mpm_worker with PHP-FPM, not mod_php with mpm_prefork.

  3. 03
    Waypoint

    Tune Apache concurrency against available memory.

  4. 04
    Waypoint

    Tune PHP-FPM workers against real process memory.

  5. 05
    Waypoint

    Keep MySQL bound to localhost unless it is intentionally remote.

  6. 06
    Waypoint

    Size InnoDB memory after the OS, Apache, and PHP-FPM have budget.

  7. 07
    Waypoint

    Put most Apache rules in virtual host config, not .htaccess, when you control the server.

  8. 08
    Migration check

    Enable HTTPS, security headers, backups, logs, and monitoring before calling the stack finished.

SEO Metadata

SEO Title Options

  1. How to Configure a LAMP Stack on Ubuntu: Apache, MySQL
  2. How to Configure a LAMP Stack on Ubuntu: Practical 2026
  3. Web Server Playbook: How to Configure a LAMP Stack on

Meta Description Options

  1. Learn How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning with a practical Web Server framework, expert mistakes, implementation steps.
  2. Full LAMP installation and optimization: MPM worker tuning, MySQL InnoDB settings, PHP-FPM pools, and .htaccess security hardening.

URL Slug

how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning

Focus Keyword

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning

Additional LSI Keywords

  • Web Server
  • LAMP
  • Ubuntu
  • Apache
  • MySQL
  • PHP-FPM
  • How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning
  • production checklist
  • implementation guide
  • best practices
  • architecture decisions
  • testing strategy

Table of Contents

Article overview

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning is the kind of topic that looks simple until it reaches production. Teams usually discover the real cost late: unclear boundaries, weak defaults, hidden maintenance work, and decisions that seemed harmless when the codebase was small.

The problem gets worse when the article, tutorial, or implementation guide only explains the happy path. This guide closes that gap with a practical framework, a comparison table, common mistakes, and a deep technical section you can use while planning real work.

Keep reading for the non-obvious part: the safest implementation is rarely the most impressive-looking one. It is the one your team can debug, test, document, and evolve without turning every future change into archaeology.

Key Takeaways

  • How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning should be evaluated as a production decision, not only as a syntax or tooling choice.
  • The best implementation keeps responsibilities visible, with clear ownership, tests, documentation, and rollback paths.
  • Search visibility improves when practical depth, structured answers, and expert examples live on the same page.

[IMAGE: A mobile-first technical article layout showing the main concept, decision table, implementation checklist, and FAQ blocks. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning expert guide for Web Server]

What How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning means

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning means applying web server knowledge to a concrete engineering decision, then turning that decision into reliable code, documentation, and operational behavior. In practice, it combines the topic's core concepts with trade-off analysis, implementation boundaries, testing strategy, and maintenance discipline.

This is the definition worth optimizing for featured snippets because it avoids hype. It tells the reader what the topic does and what a professional implementation must include.

Why it matters now

The technical web is more crowded than it was a few years ago. Thin tutorials can still get indexed, but they rarely earn trust from senior developers, buyers, AI answer systems, or teams that need production guidance.

For web server topics, the strongest content now has three layers:

  • a clear answer for fast scanning
  • a practical framework for implementation
  • expert context that explains what breaks later

That same structure helps search engines understand the page. It also helps readers decide whether the advice fits their project.

Implementation framework

Use this framework before adopting the approach described in this article.

  1. Define the user problem and the production risk.
  2. Identify the smallest reliable implementation boundary.
  3. Keep configuration, secrets, and environment-specific behavior outside the article's core logic.
  4. Add tests for the behavior that would hurt if it regressed.
  5. Document the trade-off, not only the final code.
  6. Measure the result with logs, metrics, or user-facing outcomes.
  7. Revisit the decision after real usage exposes edge cases.

The sequence is deliberately conservative. It keeps the work grounded in outcomes instead of novelty.

[IMAGE: A seven-step implementation framework with discovery, boundary design, configuration, tests, documentation, measurement, and iteration. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning implementation framework]

Practical comparison

Decision areaStrong approachWeak approachWhy it matters
ScopeSolve one clear problemMix unrelated concernsFocus improves testing and search intent
ArchitecturePut logic in explicit classes or documented boundariesHide behavior in templates or incidental callbacksFuture changes stay easier to review
Data flowPass prepared data into the view or endpointQuery or compute in presentation codeReduces regressions and performance surprises
TestingCover the risky behavior directlyTest only the happy pathCatches production failures earlier
DocumentationExplain trade-offs and limitsRepeat generic definitionsBuilds E-E-A-T and reader trust
OperationsTrack logs, metrics, and rollback stepsShip without measurementMakes the decision reversible

This table is intentionally practical. It gives a reviewer something to check before the implementation becomes expensive to change.

Expert workflow

Expert tip: "Treat How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning as a system boundary. If the next developer cannot find where the decision lives, how it is tested, and when it should be avoided, the implementation is not finished."

A useful workflow is simple:

  • Start with the smallest working example.
  • Add the constraints that exist in your real project.
  • Remove anything that only demonstrates cleverness.
  • Write down the failure modes.
  • Add links to related decisions so future readers can navigate the topic cluster.

That last point matters for both humans and search systems. A single article can answer a question; a cluster proves authority.

Common mistakes

Mistake 1: Copying a pattern without its context

A pattern that works in a small demo can fail in a real application. The missing context is usually data volume, team experience, deployment process, security requirements, or observability.

Before copying the pattern, ask what assumption made it safe in the original example.

Mistake 2: Putting business logic in the wrong layer

This is the fastest way to make future debugging expensive. In Laravel, PHP, and server-rendered websites, presentation should receive prepared data, not discover rules on its own.

Keep decision logic in models, actions, services, policies, requests, jobs, or documented helpers where it can be tested directly.

Mistake 3: Optimizing for novelty instead of maintainability

Newer tools and language features can be valuable. They can also hide simple behavior behind unfamiliar syntax.

Use the option that makes the next production incident easier to understand.

Mistake 4: Publishing without a measurement plan

If the article describes a performance, SEO, security, or architecture improvement, define how success will be checked. Logs, tests, crawl diagnostics, analytics, and user behavior are all stronger than assumptions.

[IMAGE: A common-mistakes board with context loss, wrong layer, novelty bias, and missing measurement highlighted. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning common mistakes]

Image placeholders

  • [IMAGE: A concept diagram for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning with input, decision boundary, implementation, tests, and production feedback. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning concept diagram]
  • [IMAGE: A mobile screenshot-style checklist for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning mobile checklist]
  • [IMAGE: A comparison table visualization for strong versus weak implementation choices. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning comparison table]

Video placeholder

[VIDEO: Insert a 5-8 minute YouTube walkthrough that demonstrates the main decision, the implementation boundary, the test strategy, and the production caveats for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning.]

Internal linking opportunities

Original Technical Deep Dive

The short version

A usable LAMP stack is easy:

sudo apt update
sudo apt install apache2 mysql-server php php-fpm php-mysql

A production-ready LAMP stack needs more care:

  • Apache should serve static files and pass PHP to PHP-FPM.
  • Use mpm_event or mpm_worker with PHP-FPM, not mod_php with mpm_prefork.
  • Tune Apache concurrency against available memory.
  • Tune PHP-FPM workers against real process memory.
  • Keep MySQL bound to localhost unless it is intentionally remote.
  • Size InnoDB memory after the OS, Apache, and PHP-FPM have budget.
  • Put most Apache rules in virtual host config, not .htaccess, when you control the server.
  • Enable HTTPS, security headers, backups, logs, and monitoring before calling the stack finished.

This guide uses Ubuntu-style paths and commands. It was originally framed for Ubuntu 20.04-era servers, where PHP 7.4 was common. The current examples use generic package names and PHP-FPM patterns that also fit modern Ubuntu LTS releases. Check the exact PHP version installed by your Ubuntu release before copying versioned paths.

Install the base packages

Start with an updated server:

sudo apt update
sudo apt upgrade -y

Install Apache, MySQL, PHP-FPM, and common PHP extensions:

sudo apt install -y \
  apache2 \
  mysql-server \
  php \
  php-fpm \
  php-cli \
  php-mysql \
  php-curl \
  php-mbstring \
  php-xml \
  php-zip \
  php-intl \
  php-gd \
  php-opcache

Check services:

systemctl status apache2 --no-pager
systemctl status mysql --no-pager
systemctl status 'php*-fpm' --no-pager

Check versions:

apache2 -v
mysql --version
php -v
php-fpm* -v 2>/dev/null || true

On Ubuntu, MySQL usually starts automatically after installation. Apache usually starts automatically too.

Open the firewall

If UFW is enabled, allow HTTP and HTTPS:

sudo ufw allow OpenSSH
sudo ufw allow 'Apache Full'
sudo ufw status verbose

If you prefer explicit ports:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Do not open MySQL to the internet:

sudo ufw deny 3306/tcp

If a separate application server must reach MySQL, allow only that private source IP:

sudo ufw allow from 10.0.0.20 to any port 3306 proto tcp

Prefer Apache plus PHP-FPM

Old LAMP tutorials often install libapache2-mod-php, which runs PHP inside Apache worker processes and usually forces the prefork MPM. That is simple, but it couples Apache concurrency to PHP memory and removes the main benefit of threaded Apache MPMs.

For a modern server, use Apache as the HTTP server and PHP-FPM as the PHP process manager.

Enable the Apache modules PHP-FPM needs:

sudo a2enmod proxy proxy_fcgi setenvif rewrite headers

Disable mod_php if it is installed and enabled. The exact module name depends on PHP version:

apache2ctl -M | grep php

If you see a PHP module, disable it:

sudo a2dismod php8.3 2>/dev/null || true
sudo a2dismod php8.2 2>/dev/null || true
sudo a2dismod php8.1 2>/dev/null || true
sudo a2dismod php7.4 2>/dev/null || true

Enable the PHP-FPM Apache config if Ubuntu created one:

ls /etc/apache2/conf-available/*fpm*.conf

Example:

sudo a2enconf php8.3-fpm

Then reload:

sudo apache2ctl configtest
sudo systemctl reload apache2

Use the event MPM when possible

Check the active MPM:

apache2ctl -M | grep mpm

For PHP-FPM setups, mpm_event is usually the best Apache default on modern Ubuntu servers:

sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo apache2ctl configtest
sudo systemctl restart apache2

If your package state prevents enabling mpm_event, check whether mod_php is still enabled. mod_php and threaded MPMs are not the combination you want for this stack.

[IMAGE: Supporting visual 1 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 1]

[IMAGE: Supporting visual 1 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 1]

mpm_worker can also be valid. The tuning concepts are similar: Apache has processes, threads, and a maximum number of request workers. PHP execution still happens in PHP-FPM.

Create a virtual host

Use a web root that points to public, not the project root:

sudo mkdir -p /var/www/example.com/public
sudo chown -R deploy:www-data /var/www/example.com
sudo chmod -R 2750 /var/www/example.com

Create a test file:

printf '%s\n' '<?php echo "ok\n";' | sudo tee /var/www/example.com/public/index.php

Create the vhost:

sudo nano /etc/apache2/sites-available/example.com.conf

Config:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    DocumentRoot /var/www/example.com/public

    ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined

    <Directory /var/www/example.com/public>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    <FilesMatch "\.php$">
        SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
    </FilesMatch>

    <FilesMatch "^\.">
        Require all denied
    </FilesMatch>
</VirtualHost>

Adjust the socket path:

ls /run/php/

You may see:

php8.3-fpm.sock
php8.3-fpm.pid

Enable the site:

sudo a2ensite example.com
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2

Test locally from the server:

curl -i http://127.0.0.1/ -H 'Host: example.com'

Safer rewrite rules without .htaccess

If you control the server, put rewrites in the vhost instead of .htaccess.

For a front-controller PHP app:

<Directory /var/www/example.com/public>
    Options -Indexes +FollowSymLinks
    AllowOverride None
    Require all granted

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ index.php [L]
</Directory>

This avoids per-request .htaccess filesystem checks and keeps the effective configuration in one place.

If the application requires .htaccess, allow only the override class it needs:

<Directory /var/www/example.com/public>
    Options -Indexes +FollowSymLinks
    AllowOverride FileInfo
    Require all granted
</Directory>

Avoid this unless you have a clear reason:

AllowOverride All

AllowOverride All lets .htaccess files control much more than rewrites. It is convenient, but it expands what writable application directories can do to your server behavior.

Harden public file access

Keep sensitive directories outside public.

Good:

/var/www/example.com/
  app/
  storage/
  vendor/
  .env
  public/
    index.php
    assets/

Bad:

/var/www/example.com/public/
  app/
  vendor/
  storage/
  .env
  index.php

Add defense-in-depth denies for common sensitive files:

<FilesMatch "(^\.|composer\.(json|lock)|package(-lock)?\.json|phpunit\.xml|\.env)">
    Require all denied
</FilesMatch>

<DirectoryMatch "^/var/www/example.com/(app|vendor|storage|tests|config)">
    Require all denied
</DirectoryMatch>

Do not rely on these rules to make a bad document root safe. Set the document root correctly first.

Enable HTTPS

Install Certbot:

sudo apt install -y certbot python3-certbot-apache

Issue and install a certificate:

sudo certbot --apache -d example.com -d www.example.com

Test renewal:

sudo certbot renew --dry-run

After TLS works, force HTTP to HTTPS. Certbot can do this interactively. If you write it manually:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

Then configure the HTTPS vhost as the real app vhost.

Add baseline security headers

Add headers in the HTTPS vhost:

Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"

Only add HSTS after HTTPS is stable:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Do not blindly add preload. HSTS preload is a long-term browser-level commitment. It is wrong for many staging, subdomain-heavy, or inherited-domain setups.

A Content Security Policy is valuable, but it must match the app:

Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; frame-ancestors 'self'; object-src 'none'"

That baseline may break inline scripts, third-party widgets, analytics, map embeds, and payment scripts. Test it in staging first, or start with Content-Security-Policy-Report-Only.

Apache MPM tuning

[IMAGE: Supporting visual 2 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 2]

Find the active MPM config:

ls /etc/apache2/mods-enabled/mpm_*.conf

For mpm_event, edit:

sudo nano /etc/apache2/mods-available/mpm_event.conf

Example for a small 2 GB server:

<IfModule mpm_event_module>
    StartServers             2
    MinSpareThreads         25
    MaxSpareThreads         75
    ThreadLimit             64
    ThreadsPerChild         25
    MaxRequestWorkers      100
    MaxConnectionsPerChild 5000
</IfModule>

The important number is MaxRequestWorkers. It caps simultaneous Apache request workers. For worker and event MPMs, it is the total thread count available to serve requests.

A simple memory budget:

available memory for Apache =
  total RAM
  - OS reserve
  - MySQL budget
  - PHP-FPM max children * average PHP child memory
  - other services

Apache event workers are usually much smaller than PHP-FPM workers, but they are not free. Do not set MaxRequestWorkers to a huge number because a benchmark tool made it look good for static files.

[IMAGE: Supporting visual 2 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 2]

Check for saturation:

sudo tail -f /var/log/apache2/error.log

If Apache logs that it reached MaxRequestWorkers, you have three choices:

  • raise the limit if memory allows it;
  • reduce request time so workers free faster;
  • add another server.

Raising concurrency without memory budget can push the server into swap and make every request slower.

PHP-FPM pool tuning

Find the active pool config:

ls /etc/php/*/fpm/pool.d/www.conf

Edit it:

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Small server baseline:

[www]
user = www-data
group = www-data

listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500

request_terminate_timeout = 60s
request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-slow.log

clear_env = yes
security.limit_extensions = .php

Calculate pm.max_children from real memory, not guesses.

Get average PHP-FPM process size under traffic:

ps -ylC php-fpm8.3 --sort:rss

Or:

ps -o rss= -C php-fpm8.3 | awk '{sum+=$1; count++} END {if (count) print int(sum/count/1024) " MB"}'

Formula:

pm.max_children =
  memory available for PHP-FPM / average PHP-FPM child memory

Example:

Memory available for PHP-FPM: 900 MB
Average PHP child memory: 75 MB
pm.max_children: 12

Reload after changes:

sudo php-fpm8.3 -t
sudo systemctl reload php8.3-fpm
sudo systemctl reload apache2

Check for saturation:

sudo journalctl -u php8.3-fpm -f

If you see server reached pm.max_children, either:

  • PHP workers need less time per request;
  • pm.max_children is too low for available memory;
  • traffic exceeds the server's capacity;
  • slow external services are holding PHP workers open.

Do not raise pm.max_children until the memory math says the server can survive it.

Enable OPcache for web requests

Find the FPM php.ini:

php --ini
ls /etc/php/*/fpm/php.ini

Edit FPM config, not only CLI config:

sudo nano /etc/php/8.3/fpm/conf.d/10-opcache.ini

Baseline:

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.save_comments=1
opcache.jit=off

For controlled deployments, you can disable timestamp validation and reload PHP-FPM on deploy:

opcache.validate_timestamps=0

Then your deployment must reload FPM:

sudo systemctl reload php8.3-fpm

If you cannot guarantee a reload on every deploy, leave timestamp validation on.

Production PHP settings

Create an app-specific FPM INI file:

sudo nano /etc/php/8.3/fpm/conf.d/99-production.ini

Baseline:

expose_php=0
display_errors=0
display_startup_errors=0
log_errors=1
error_log=/var/log/php_errors.log
memory_limit=256M
max_execution_time=30
max_input_time=30
post_max_size=32M
upload_max_filesize=32M
session.cookie_secure=1
session.cookie_httponly=1
session.cookie_samesite=Lax

Reload:

sudo systemctl reload php8.3-fpm

Verify through the web SAPI, not only CLI. CLI and FPM can load different php.ini files.

Temporary diagnostic file:

printf '%s\n' '<?php phpinfo();' | sudo tee /var/www/example.com/public/_phpinfo.php

Open it through the browser, confirm the FPM settings, then remove it:

sudo rm /var/www/example.com/public/_phpinfo.php

[IMAGE: Supporting visual 3 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 3]

Never leave phpinfo() public on production.

MySQL first secure setup

Ubuntu's MySQL package creates a local root account that commonly uses socket authentication. Connect with:

sudo mysql

Create an application database and user:

CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

CREATE USER 'app'@'localhost'
  IDENTIFIED WITH caching_sha2_password
  BY 'replace-with-a-long-random-password';

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP
  ON app.*
  TO 'app'@'localhost';

FLUSH PRIVILEGES;

Use a narrower grant set if migrations run from a separate deployment account. The application runtime often does not need CREATE, ALTER, INDEX, or DROP.

Check MySQL network binding:

sudo ss -tap | grep mysql

A local-only database should show 127.0.0.1:mysql or a Unix socket, not 0.0.0.0:3306.

If needed, edit:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Keep local binding:

bind-address = 127.0.0.1

Restart:

sudo systemctl restart mysql

MySQL InnoDB memory tuning

Before changing MySQL memory, decide the server role:

Server roleInnoDB buffer pool starting point
Small all-in-one LAMP server25 to 40 percent of RAM
Dedicated MySQL server50 to 75 percent of RAM
Tiny 1 GB VPSBe conservative; avoid starving PHP-FPM and the OS

[IMAGE: Supporting visual 3 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 3]

For an all-in-one 4 GB VPS:

OS and filesystem cache: 700 MB
Apache: 200 MB
PHP-FPM: 1200 MB
MySQL buffer pool: 1200 MB
Other services and burst room: 700 MB

Create a local MySQL tuning file:

sudo nano /etc/mysql/mysql.conf.d/99-lamp.cnf

Example:

[mysqld]
innodb_buffer_pool_size = 1G
innodb_log_buffer_size = 64M
innodb_redo_log_capacity = 512M
max_connections = 80
table_open_cache = 2000
tmp_table_size = 64M
max_heap_table_size = 64M
slow_query_log = ON
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 0.5
log_queries_not_using_indexes = OFF

Notes:

  • innodb_buffer_pool_size is usually the most important InnoDB memory setting.
  • innodb_log_buffer_size helps large transactions avoid extra redo log flushes.
  • innodb_redo_log_capacity replaced old innodb_log_file_size style tuning in newer MySQL.
  • max_connections must fit memory. Each connection can allocate memory.
  • Slow query logging is for diagnosis. Watch disk usage.

Validate and restart:

sudo mysqld --validate-config
sudo systemctl restart mysql

If mysqld --validate-config is unavailable or unsuitable for your package, use:

sudo journalctl -u mysql -n 100 --no-pager

After restart:

sudo mysql -e "SHOW VARIABLES WHERE Variable_name IN ('innodb_buffer_pool_size','innodb_redo_log_capacity','max_connections');"

Use mysqltuner carefully

Install:

sudo apt install -y mysqltuner

Run only after the server has handled representative traffic for at least a day:

sudo mysqltuner

Treat output as suggestions, not commands. mysqltuner does not know your deploy schedule, queue load, traffic spikes, backup window, or memory budget for PHP-FPM.

The best MySQL tuning is still query tuning:

  • Add indexes that match real queries.
  • Fix N+1 query patterns.
  • Avoid loading giant result sets.
  • Paginate by keyset for high-volume lists.
  • Measure with EXPLAIN and the slow query log.

[IMAGE: Supporting visual 4 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 4]

Align Apache, PHP-FPM, and MySQL limits

Bad all-in-one setup:

Apache MaxRequestWorkers = 400
PHP-FPM pm.max_children = 100
MySQL max_connections = 500
RAM = 2 GB

That stack can promise far more concurrency than memory can pay for.

Better small setup:

Apache MaxRequestWorkers = 100
PHP-FPM pm.max_children = 12
MySQL max_connections = 80
RAM = 2 GB

The Apache number can be higher than PHP-FPM because Apache also serves static files and handles keep-alive connections. PHP-FPM is the expensive layer for dynamic PHP requests.

Watch the bottleneck:

SymptomLikely pressure
Apache reaches MaxRequestWorkersHTTP request concurrency, slow upstreams, too low Apache limit
PHP-FPM reaches pm.max_childrenDynamic PHP requests exceed worker capacity
MySQL hits max_connectionsToo many app connections, no pooling, slow queries
System swapsMemory limits are too high for the server
CPU pinned, low I/O waitPHP CPU work, compression, TLS, MySQL CPU queries
High I/O waitDisk, MySQL, logs, swap, backups

Tune one layer at a time. If you change Apache, PHP-FPM, MySQL, OPcache, and application code together, you will not know which change mattered.

Add log rotation awareness

Ubuntu packages usually install logrotate rules for Apache, PHP-FPM, and MySQL. Verify them:

ls /etc/logrotate.d/
cat /etc/logrotate.d/apache2
cat /etc/logrotate.d/mysql-server 2>/dev/null || true

Check disk:

df -h
sudo du -sh /var/log/*

Slow query logs, access logs, and app logs can fill a small VPS quickly. A full disk can take down MySQL and make deployments fail.

[IMAGE: Supporting visual 4 for How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning, showing How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning decisions, examples, and LAMP, Ubuntu, Apache. Alt: How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning how-configure-lamp-stack-ubuntu-apache-mysql-php-tuning visual 4]

Add basic health checks

Apache config:

<VirtualHost *:80>
    ServerName example.com

    Alias /healthz /var/www/example.com/public/healthz.txt
</VirtualHost>

File:

echo ok | sudo tee /var/www/example.com/public/healthz.txt

Check:

curl -fsS http://127.0.0.1/healthz -H 'Host: example.com'

For PHP-FPM status, configure a private endpoint only:

pm.status_path = /fpm-status
ping.path = /fpm-ping
ping.response = pong

Then restrict access in Apache:

<LocationMatch "^/(fpm-status|fpm-ping)$">
    Require ip 127.0.0.1
</LocationMatch>

Do not expose FPM status pages publicly.

Deployment checklist

Before putting traffic on the server:

[ ] Apache serves only the public document root.
[ ] PHP runs through PHP-FPM, not mod_php.
[ ] Active MPM is event or worker.
[ ] Apache config passes apache2ctl configtest.
[ ] PHP-FPM config passes php-fpm -t.
[ ] MySQL config validates or starts cleanly.
[ ] UFW allows only SSH, HTTP, and HTTPS publicly.
[ ] MySQL is bound to localhost or a private interface.
[ ] HTTPS works and renewal dry run passes.
[ ] Security headers are tested.
[ ] .htaccess is disabled or narrowly scoped.
[ ] OPcache is enabled for FPM.
[ ] PHP display_errors is off.
[ ] PHP memory_limit matches app needs.
[ ] PHP-FPM pm.max_children fits memory.
[ ] Apache MaxRequestWorkers fits memory.
[ ] MySQL InnoDB buffer pool fits memory.
[ ] Slow query log is enabled with disk monitoring.
[ ] Backups are configured and restore-tested.
[ ] Logs rotate.
[ ] Health checks work.
[ ] Monitoring alerts on CPU, memory, disk, 5xx, PHP-FPM saturation, MySQL errors.

FAQ

What is How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning?

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning is a practical web server topic that should be evaluated through implementation scope, production risk, testing, documentation, and long-term maintainability.

When should a team use How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning?

Use How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning when it solves a real project constraint, improves clarity, or reduces operational risk. Avoid it when it only adds novelty or hides behavior from future maintainers.

What is the biggest risk with How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning?

The biggest risk is copying a pattern without its context. Production systems need clear boundaries, rollback options, tests, and observability before a technique becomes dependable.

How do you test How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning?

Test the smallest unit that owns the behavior, then add integration coverage for the path users or systems actually rely on. Include failure cases, configuration differences, and regression checks.

How does How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning affect SEO and AI search visibility?

It improves visibility when the article gives a direct answer, expert context, structured headings, internal links, trustworthy references, and FAQ content that matches the visible page.

Conclusion

How to Configure a LAMP Stack on Ubuntu: Apache, MySQL & PHP Tuning is worth doing when the implementation improves clarity, reliability, or delivery speed. It is not worth doing when it hides ownership, increases operational risk, or makes the system harder to explain.

Use the framework above as a review checklist. Then connect this topic to the rest of the project documentation so readers can move from concept to implementation without losing context.

Top