What a LAMP Stack Actually Is
A LAMP stack is a group of four open-source software components that work together to serve dynamic web content. The acronym stands for Linux, Apache, MySQL, and PHP. Each component has a specific role: Linux provides the server operating system, Apache handles HTTP requests and serves web pages, MySQL manages the database where your application data lives, and PHP processes requests that require dynamic content generation.
Understanding what each piece does matters when something breaks or when you need to optimise performance. Rather than following steps blindly, knowing the role of each component helps you troubleshoot, maintain, and secure your server with confidence. This guide walks through installing and configuring a complete LAMP stack on Ubuntu, with the security steps and configuration choices that make a server suitable for production use rather than just functional in a test environment.
Prerequisites Before You Begin
You need a clean Ubuntu server with a non-root user that has sudo privileges. The examples in this guide target Ubuntu 16.04, though the steps are similar across recent Ubuntu versions. You also need a static IP address or a DNS record pointing to your server so you can reach it after setup.
Connect to your server via SSH using your non-root user:
ssh username@your_server_ip
Once connected, update the package lists and upgrade any outdated packages:
sudo apt update && sudo apt upgrade -y
Keeping packages updated is essential on any server. Updates patch security vulnerabilities and stabilise the software you are running. Set up a routine for this rather than doing it only when you remember.
Installing Apache Web Server
Apache is available in the Ubuntu package repositories, which makes installation straightforward. Install it with:
sudo apt install apache2 -y
After installation, Apache starts automatically. Verify it is running:
sudo systemctl status apache2
You should see "active (running)" in the output. If the service is not running, start it with:
sudo systemctl start apache2
Allow Apache through the firewall before proceeding. Ubuntu ships with UFW (Uncomplicated Firewall). Check its current status:
sudo ufw status
By default, UFW blocks all incoming connections. Apache registers itself with UFW and opens the correct ports. Enable the Apache Full profile, which allows both HTTP on port 80 and HTTPS on port 443:
sudo ufw allow 'Apache Full'
Test that Apache is serving pages by visiting your server's IP address in a browser. You should see the default Apache landing page. From the command line, test it with curl:
curl http://your_server_ip
The default Apache document root is /var/www/html/. The main Apache configuration file is /etc/apache2/apache2.conf, and site configurations live in /etc/apache2/sites-available/.
Installing MySQL Database Server
MySQL is the database engine that stores your application data. Install it with:
sudo apt install mysql-server -y
During installation, you will be prompted to set a root password for MySQL. Choose a strong, unique password and store it somewhere secure. The MySQL root account is separate from the Linux root account. It only has access to the database system itself, not the server operating system.
Start MySQL and enable it to start automatically on boot:
sudo systemctl start mysql
sudo systemctl enable mysql
Run the MySQL secure installation script, which removes test databases, anonymous user accounts, and restricts remote root access:
sudo mysql_secure_installation
Answer the prompts as follows: set a root password if not already set, remove anonymous users, disallow root login remotely, remove the test database, and reload privilege tables. These steps are not optional on a production server. Test databases and anonymous access are security risks that attackers commonly exploit.
Log into MySQL to verify the installation:
mysql -u root -p
You should see the MySQL prompt. Type EXIT; to quit.
Once your MySQL server is running, you may want to explore ways to improve query performance. A well-configured database with proper indexing handles application requests efficiently and keeps response times consistent as data grows.
Creating a Database and User for Your Application
Do not use the root MySQL account for your application. Create a dedicated database and user with appropriate permissions for your specific application needs:
CREATE DATABASE webapp_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'webapp_user'@'localhost' IDENTIFIED BY 'your_strong_password_here';
GRANT ALL PRIVILEGES ON webapp_db.* TO 'webapp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Replace webapp_db, webapp_user, and the password with values specific to your application. This user can only connect from localhost and only has access to the webapp_db database. Limiting permissions follows the principle of least privilege, which reduces the impact if any application credentials are compromised.
Installing PHP
PHP processes dynamic content and connects your application to MySQL. Install PHP and the most common extensions needed for web applications:
sudo apt install php php-mysql libapache2-mod-php php-cli php-cgi -y
The php-mysql extension allows PHP to communicate with MySQL. The libapache2-mod-php package enables PHP as an Apache module, which is the most common configuration. The php-cli package provides the PHP command-line interface, which is useful for cron jobs, maintenance scripts, and testing.
After installation, restart Apache to load the PHP module:
sudo systemctl restart apache2
Verify PHP is working by creating a test file:
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
Visit http://your_server_ip/info.php in a browser. You should see a PHP information page showing the version, loaded modules, and configuration. Delete this file immediately after testing. The phpinfo page exposes server information that should not be public:
sudo rm /var/www/html/info.php
For better security, review the PHP configuration and disable functions that are commonly exploited in web applications. Edit the PHP configuration file. The path varies depending on your PHP version. For Ubuntu 16.04 with PHP 7.0, it is typically located at /etc/php/7.0/apache2/php.ini:
sudo nano /etc/php/7.0/apache2/php.ini
Find the disable_functions directive and add dangerous functions that allow system command execution. Only disable functions you are certain your application does not need. Common functions to restrict include those that execute shell commands or expose system information. After editing, restart Apache:
sudo systemctl restart apache2
Also set expose_php = Off to prevent PHP from advertising itself in HTTP headers. Hiding the PHP version reduces the information available to potential attackers scanning for known vulnerabilities.
Configuring Apache Virtual Hosts
Apache's default configuration serves content from /var/www/html/ for any request. When you host multiple sites or want cleaner organisation, Virtual Hosts let you separate configurations. Create a Virtual Host for your domain:
sudo mkdir -p /var/www/html/yourdomain.co.uk
sudo chown -R $USER:$USER /var/www/html/yourdomain.co.uk
sudo chmod -R 755 /var/www/html
Create the Virtual Host configuration file:
sudo nano /etc/apache2/sites-available/yourdomain.co.uk.conf
Add the following configuration, replacing yourdomain.co.uk with your actual domain:
<VirtualHost *:80>
ServerName yourdomain.co.uk
ServerAlias www.yourdomain.co.uk
ServerAdmin [email protected]
DocumentRoot /var/www/html/yourdomain.co.uk
<Directory /var/www/html/yourdomain.co.uk>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/yourdomain.co.uk-error.log
CustomLog ${APACHE_LOG_DIR}/yourdomain.co.uk-access.log combined
</VirtualHost>
The -Indexes option prevents directory listing if no index file is present. FollowSymLinks allows symbolic links, which many applications need. AllowOverride All enables .htaccess files, which WordPress and other CMS platforms require.
Enable the site and disable the default site:
sudo a2ensite yourdomain.co.uk.conf
sudo a2dissite 000-default.conf
sudo systemctl reload apache2
Test the Apache configuration for syntax errors:
sudo apache2ctl configtest
If you see "Syntax OK", the configuration is valid. Any error message will indicate the file and line number of the problem, which makes fixing typos straightforward.
Installing Let's Encrypt SSL Certificate
HTTPS is not optional for any production website. Search engines flag HTTP-only sites as insecure, and browsers display warnings to visitors. Let's Encrypt provides free SSL certificates, and Certbot automates the installation and renewal process.
Install Certbot and its Apache plugin:
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:certbot/certbot -y
sudo apt update
sudo apt install python-certbot-apache -y
Obtain and install the certificate for your domain:
sudo certbot --apache -d yourdomain.co.uk -d www.yourdomain.co.uk
Certbot will ask for an email address for renewal reminders and offer options for HTTPS redirection. Choose to redirect all HTTP traffic to HTTPS. The certificate is valid for 90 days. Certbot sets up an automated renewal cron job to handle renewals, but it is worth testing the renewal process to confirm it works on your system.
If you prefer to run HTTPS on a different port or use a reverse proxy setup, there are alternative approaches to securing your traffic. A reverse proxy can handle SSL termination and route requests to your LAMP stack.
Setting Up a Firewall Baseline
A properly configured firewall is one of the simplest and most effective security measures for any server. Configure UFW with a strict baseline that allows only the traffic your server needs:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 'Apache Full'
sudo ufw enable
The default deny for incoming blocks all unsolicited traffic. SSH access is allowed so you do not lock yourself out of the server. Apache Full permits web traffic on ports 80 and 443. The allow rules are evaluated in order, so SSH and Apache Full override the default deny for their specific ports.
Before enabling UFW, ensure you have SSH access configured and allowed. If you lose your SSH connection after enabling the firewall, you may be locked out of your server, depending on your hosting provider's recovery options.
Testing the Complete Stack
Create a test PHP page that connects to MySQL to verify the entire stack is working together:
sudo nano /var/www/html/yourdomain.co.uk/test.php
Add the following content, replacing the database credentials with your own:
<?php
$conn = new mysqli('localhost', 'webapp_user', 'your_password', 'webapp_db');
if ($conn->connect_error) {
die('Connection failed: ' . $conn->connect_error);
}
echo 'LAMP stack is working correctly';
$conn->close();
?>
Visit https://yourdomain.co.uk/test.php in your browser. You should see the success message. Remove the test file after confirming everything works. Test files left on production servers are a security risk.
Installing phpMyAdmin for Database Management
While you can manage MySQL entirely from the command line, phpMyAdmin provides a web-based interface that makes common tasks easier, such as importing exports, visualising table structures, and running queries without writing SQL. If you prefer a graphical interface for database management, install phpMyAdmin after your LAMP stack is working:
sudo apt install phpmyadmin -y
During installation, select Apache2 when prompted and choose to configure database for phpmyadmin with dbconfig-common. You will need the MySQL root password you set earlier.
Secure phpMyAdmin further by configuring Apache to restrict access and considering authentication layer options. The phpMyAdmin interface should never be publicly accessible without additional protection since it is a common target for automated attacks.
What Comes Next With Your LAMP Stack
With a LAMP stack installed, you have a functional web server ready for application deployment. What you do next depends on what you are building. A PHP application like WordPress, Laravel, or a custom application sits on top of this foundation.
If you plan to run WordPress, the LAMP stack you have configured provides exactly what WordPress needs. You can proceed with installing WordPress on Ubuntu with your LAMP stack by creating a database, downloading WordPress, and configuring the appropriate permissions.
The security hardening steps in this guide represent a baseline. Further configuration depends on what the server will host. A public-facing application needs more attention than an internal development server.
Regular Maintenance Tasks
- Apply updates regularly: Run
sudo apt update && sudo apt upgrade -yconsistently, ideally on a weekly schedule or more frequently for security patches. - Monitor disk usage: Databases and log files grow over time. Set up monitoring or check manually to avoid running out of space.
- Set up log rotation: Apache and MySQL generate logs that can consume significant disk space if left unmanaged.
- Test backups before you need them: Verify that your backup process actually restores data correctly.
- Review access logs: Unusual patterns in access logs can indicate scanning activity or attempted exploitation.