The LAMP stack — Linux, Apache, MySQL, PHP — still powers a huge slice of the web because it is fast, predictable, and well-documented. This guide walks through a production-grade install on Ubuntu 24.04, including TLS via Let's Encrypt and the small-but-vital tuning that the default packages leave on the floor.
Prerequisites
- Ubuntu 24.04 LTS with a working sudo account.
- A public DNS record (A / AAAA) pointing at the server.
- Outbound TCP/443 reachable for ACME challenges and package downloads.
- The hardening recipe from the SSH + UFW + Fail2ban guide already applied.
Step 1: Install Apache
sudo apt update
sudo apt install -y apache2
sudo systemctl enable --now apache2
sudo systemctl status apache2 --no-pager
Open port 80 and 443 in UFW:
sudo ufw allow 'Apache Full'
sudo ufw status
Confirm the default page renders by visiting http://your.server.ip/.
Step 2: Install MySQL 8 and run the secure-installation wizard
sudo apt install -y mysql-server
sudo systemctl enable --now mysql
sudo mysql_secure_installation
Answer the prompts:
| Prompt | Recommended answer |
| --- | --- |
| Validate password component? | Y then 2 (strong) |
| Set root password | A 32-char random string from pwgen -s 32 1 |
| Remove anonymous users? | Y |
| Disallow root login remotely? | Y |
| Remove test database? | Y |
| Reload privilege tables? | Y |
Create an application user and database from the MySQL prompt:
CREATE DATABASE skyline_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'skyline'@'localhost' IDENTIFIED BY 'change-this-now';
GRANT ALL PRIVILEGES ON skyline_app.* TO 'skyline'@'localhost';
FLUSH PRIVILEGES;
Step 3: Install PHP 8.3 and the modules Apache needs
Ubuntu 24.04 ships PHP 8.3 as the default. Add the FPM stack and the modules you will typically need:
sudo apt install -y php php-cli php-fpm php-mysql php-mbstring php-xml php-curl \
php-zip php-gd php-bcmath php-intl php-redis libapache2-mod-php
Wire Apache to run PHP via mod_php for simple setups, or switch to FPM for higher concurrency:
# mod_php (default after the package install) — fine for low traffic
sudo a2enmod php8.3
sudo systemctl restart apache2
# FPM (preferred for production)
sudo a2dismod php8.3
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2
Drop a one-line check and confirm:
echo "<?php phpinfo();" | sudo tee /var/www/html/info.php > /dev/null
curl -s http://localhost/info.php | head -20
sudo rm /var/www/html/info.php
Step 4: Configure a virtual host
sudo mkdir -p /var/www/example.sa/public_html
sudo chown -R www-data:www-data /var/www/example.sa
Drop /etc/apache2/sites-available/example.sa.conf:
<VirtualHost *:80>
ServerName example.sa
ServerAlias www.example.sa
DocumentRoot /var/www/example.sa/public_html
<Directory /var/www/example.sa/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example.sa-error.log
CustomLog ${APACHE_LOG_DIR}/example.sa-access.log combined
</VirtualHost>
Enable the site and reload:
sudo a2ensite example.sa.conf
sudo a2enmod rewrite headers
sudo apachectl configtest
sudo systemctl reload apache2
Step 5: TLS with Let's Encrypt and Certbot
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d example.sa -d www.example.sa \
--redirect --agree-tos -m ops@example.sa --no-eff-email
Certbot adds the redirect and renewal timer automatically. Verify both:
curl -fI https://example.sa/ | head
sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run
Step 6: A handful of tuning knobs
/etc/php/8.3/fpm/php.ini— raisememory_limitto256M,upload_max_filesizeandpost_max_sizeto suit your app, and setexpose_php = Off./etc/php/8.3/fpm/pool.d/www.conf— setpm = dynamic,pm.max_children = (RAM / avg_req_mem), andpm.start_servers = 4./etc/mysql/mysql.conf.d/mysqld.cnf— setinnodb_buffer_pool_sizeto roughly 60 % of RAM on a dedicated DB host.
Restart the affected services:
sudo systemctl restart php8.3-fpm mysql apache2
Conclusion
You now have a production LAMP host with TLS, a dedicated database user, and the tuning that matters most. Drop your application into /var/www/example.sa/public_html and you are off.
Next steps
- Layer on the Docker recipe for sidecar services like Redis or background workers.
- Re-apply the hardening guide after any major reconfiguration.
- Schedule the patch policy so the stack keeps itself current.
Comments
0 total · 0 threads