Tutorials  /  Ubuntu

Install & Secure LAMP Stack on Ubuntu 20.04

Ccentron Redaktion · October 2025 ·13 min read ·Ubuntu, Tutorial

The LAMP stack—Linux, Apache, MySQL, and PHP—is a suite of open-source tools for building and hosting dynamic web applications. In this setup:

  • Linux serves as the operating system
  • Apache delivers web content
  • MySQL manages databases
  • PHP processes dynamic content

This guide shows how to install and configure the LAMP stack on Ubuntu 20.04 to host web applications on your server.

Prerequisites

Before starting, make sure you have the following:

  • An Ubuntu 20.04 server
  • SSH access as a non-root user with sudo privileges
  • A new A record for your domain pointing to the server’s IP address
  • An updated server
VM

Matching infrastructure at centron

Ubuntu servers without your own hardware: ccloud³ VMs with full root access from €3.12 per month, billed by the hour and ready in seconds. Rent a cloud server →

Install Apache

Ubuntu 20.04’s default APT repositories provide the latest Apache version. Follow these steps to update the package index and install Apache.

Update the package index

Console
$ sudo apt update

Install Apache

Console
$ sudo apt install apache2 -y

Start Apache

Console
$ sudo systemctl start apache2

Enable Apache to start on boot

Console
$ sudo systemctl enable apache2

Check Apache service status

Console
$ sudo systemctl status apache2

Sample output:

YAML
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2025-04-06 10:56:28 UTC; 20s ago
       Docs: https://httpd.apache.org/docs/2.4/
   Main PID: 2622 (apache2)
      Tasks: 55 (limit: 9415)
     Memory: 6.9M
     CGroup: /system.slice/apache2.service
             ├─2622 /usr/sbin/apache2 -k start
             ├─2623 /usr/sbin/apache2 -k start
             └─2624 /usr/sbin/apache2 -k start

Allow HTTP traffic through the firewall

Console
$ sudo ufw allow 80/tcp

Open a browser and visit your domain or server IP (for example http://SERVER-IP) to confirm that Apache’s default page appears.

Install MySQL

MySQL provides the database backend for the LAMP stack, though you can use MariaDB as an alternative. Ubuntu 20.04’s default repositories contain the latest MySQL package. Use these commands to install MySQL via APT.

Install the MySQL server package

Console
$ sudo apt install -y mysql-server

Enable MySQL to start on boot

Console
$ sudo systemctl enable mysql

Start MySQL

Console
$ sudo systemctl start mysql

Check MySQL service status

Console
$ sudo systemctl status mysql

Sample output:

YAML
● mysql.service - MySQL Community Server
     Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2025-04-06 10:58:51 UTC; 41s ago
   Main PID: 17189 (mysqld)
     Status: "Server is operational"
     Tasks: 38 (limit: 9415)
     Memory: 364.8M
     CGroup: /system.slice/mysql.service
             └─17189 /usr/sbin/mysqld

If the status shows active (running), the MySQL server is operational.

Secure the MySQL installation

Run the MySQL secure installation script to remove unsafe defaults and enable authentication.

Console
$ sudo mysql_secure_installation

When prompted, configure the options as follows:

  • Enable password validation: y
  • Choose password policy: 2 for strong passwords
  • Remove anonymous users: y
  • Disallow remote root login: y
  • Remove test database: y
  • Reload privilege tables: y

You should see a confirmation similar to “Success. All done!” when the configuration is complete.

Log in to the MySQL console as root

Console
$ sudo mysql

Set a strong password for the root user

Replace Strong@@password123 with your own secure password.

Code
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Strong@@password123';

Apply privilege changes

Code
mysql> FLUSH PRIVILEGES;

Exit the MySQL console

Code
mysql> EXIT;

Log in again with the new password

Console
$ mysql -u root -p

Create a sample database

Code
mysql> CREATE database content_database;

List databases to confirm

Code
mysql> SHOW DATABASES;

Expected output:

Code
+--------------------+
| Database           |
+--------------------+
| information_schema |
| content_database   |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

Create a new MySQL user

Create a user such as dbadmin with a strong password (replace the example password with your own).

Code
mysql> CREATE USER 'dbadmin'@'localhost' IDENTIFIED BY 'Strong@@password123';

Grant privileges on the database

Code
mysql> GRANT ALL PRIVILEGES ON content_database.* TO 'dbadmin'@'localhost';

Apply privilege changes

Code
mysql> FLUSH PRIVILEGES;

Exit the MySQL shell

Code
mysql> EXIT;

Install PHP and Configure PHP-FPM

PHP is a crucial part of the LAMP stack, responsible for processing dynamic content and communicating with the MySQL database. PHP-FPM (FastCGI Process Manager) improves performance by handling PHP requests through a pool of worker processes.

Install PHP and PHP-FPM

Console
$ sudo apt install -y php php-fpm

Install common PHP extensions

Console
$ sudo apt install -y php-mysql php-opcache php-cli libapache2-mod-php

This command installs:

  • php-mysql: Enables PHP to connect to MySQL
  • libapache2-mod-php: Allows Apache to execute PHP scripts
  • php-opcache: Caches precompiled PHP scripts for faster performance
  • php-cli: Provides command line interface access to PHP

Check the PHP version

Console
$ php -v

Sample output:

Code
PHP 7.4.3-4ubuntu2.29 (cli) (built: Mar 25 2025 18:57:03) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3-4ubuntu2.29, Copyright (c), by Zend Technologies

Start and enable PHP-FPM

Start the PHP-FPM service according to your installed version (for example, PHP 7.4):

Console
$ sudo systemctl start php7.4-fpm
Console
$ sudo systemctl enable php7.4-fpm

Check PHP-FPM status

Console
$ sudo systemctl status php7.4-fpm

Sample output:

YAML
● php7.4-fpm.service - The PHP 7.4 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php7.4-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2025-04-06 11:11:45 UTC; 10min ago
       Docs: man:php-fpm7.4(8)
    Process: 27868 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/7.4/fpm/pool.d/www.conf 74 (code=exited, status=0/SUCCESS)
   Main PID: 27851 (php-fpm7.4)
     Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
      Tasks: 3 (limit: 9415)
     Memory: 7.3M
     CGroup: /system.slice/php7.4-fpm.service
             ├─27851 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
             ├─27866 php-fpm: pool www
             └─27867 php-fpm: pool www

Configure PHP-FPM

PHP-FPM improves PHP application performance by managing worker process pools. Adjust the default pool settings based on your server’s memory. Follow these steps to integrate PHP-FPM with Apache and fine-tune the pool configuration.

Enable Apache modules required for PHP-FPM

Console
$ sudo a2enmod proxy_fcgi setenvif

This command enables:

  • proxy_fcgi: Allows Apache to act as a proxy for PHP-FPM
  • setenvif: Sets environment variables to connect Apache and PHP-FPM

Enable default PHP-FPM configuration

Console
$ sudo a2enconf php7.4-fpm

Restart Apache to apply changes

Console
$ sudo systemctl restart apache2

Edit PHP-FPM pool configuration

Console
$ cd /etc/php/7.4/fpm/pool.d/
Console
$ sudo nano /etc/php/7.4/fpm/pool.d/www.conf

Verify the default pool name:

Code
[www]

Ensure the following directives are set to www-data:

Code
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data

Adjust these settings as needed:

  • pm: Set to dynamic to let PHP child processes scale with demand.
  • pm.start_servers: Number of child processes to start (default: 2).
  • pm.max_children: Maximum concurrent child processes (default: 5).
  • pm.min_spare_servers: Minimum idle child processes (default: 1).
  • pm.max_spare_servers: Maximum idle child processes (default: 3).
  • pm.max_requests: Number of requests a child process serves before recycling.

Save and close the file.

Restart PHP-FPM to apply changes

Console
$ sudo systemctl restart php7.4-fpm

Configure Apache with PHP-FPM

Apache interacts with PHP-FPM through the mod_proxy_fcgi module, using either a UNIX socket or the default TCP port 9000. Follow these steps to create a new Apache virtual host that connects to PHP-FPM through the UNIX socket.

Remove the default Apache virtual host configuration

Console
$ sudo rm -rf /etc/apache2/sites-enabled/000-default.conf && sudo rm -rf /etc/apache2/sites-available/000-default.conf

Create a new Apache virtual host configuration file

For example, create app.example.com.conf:

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

Add the following content (replace app.example.com with your actual domain):

Code
ServerAdmin webmaster@app.example.com
ServerName app.example.com
DocumentRoot /var/www/html/app.example.com


    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted



   SetHandler "proxy:unix:/var/run/php/php7.4-fpm.sock|fcgi://localhost/"


ErrorLog ${APACHE_LOG_DIR}/app.example.com_error.log
CustomLog ${APACHE_LOG_DIR}/app.example.com_access.log combined

This configuration:

  • Listens on port 80 for the domain app.example.com.
  • Sets the web root to /var/www/html/app.example.com.
  • Forwards PHP file requests to the PHP-FPM socket via FastCGI.
  • Defines custom paths for error and access logs.

Enable the new Apache virtual host

Console
$ sudo a2ensite app.example.com.conf

Test the Apache configuration

Console
$ sudo apache2ctl configtest

Sample output:

Code
Syntax OK

Create the virtual host web root directory

Console
$ sudo mkdir -p /var/www/html/app.example.com

Create a sample PHP file

Console
$ sudo nano /var/www/html/app.example.com/info.php

Add the following PHP code:

Code
<!--?php phpinfo(); ?-->

This script displays PHP version details and enabled modules in your browser.

Restart Apache to apply changes

Console
$ sudo systemctl restart apache2

Finally, open your domain in a browser (for example http://app.example.com/info.php) to confirm that the PHP information page is displayed.

Secure the Server

Ubuntu 20.04 servers can have the Uncomplicated Firewall (UFW) enabled. Apache serves dynamic web content over HTTP port 80, while MySQL (3306) and PHP-FPM (9000) use internal TCP ports. Follow these steps to allow traffic on port 80 and configure trusted SSL certificates for HTTPS on port 443.

Configure the Firewall

Check that the firewall is active:

Console
$ sudo ufw status

Sample output:

Code
Status: active
...

List available UFW application profiles:

Console
$ sudo ufw app list

Sample output:

Code
Apache
Apache Full
Apache Secure
OpenSSH

Allow the Apache Full profile to enable both HTTP and HTTPS:

Console
$ sudo ufw allow "Apache Full"

Reload the firewall to apply the changes:

Console
$ sudo ufw reload

Check UFW status again to confirm that Apache connection rules are active:

Console
$ sudo ufw status

Sample output:

Code
To                         Action      From
--                         ------      ----
1022/tcp                   ALLOW       Anywhere
Apache Full                ALLOW       Anywhere
1022/tcp (v6)              ALLOW       Anywhere (v6)
Apache Full (v6)           ALLOW       Anywhere (v6)

Generate Trusted Let's Encrypt SSL Certificates

Install the Certbot client using Snap:

Console
$ sudo snap install certbot --classic

Request a new SSL certificate (replace app.example.com and admin@example.com with your own domain and email):

Console
$ sudo certbot --apache -d app.example.com -m admin@example.com --agree-tos

Sample output:

Code
Requesting a certificate for app.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/app.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/app.example.com/privkey.pem
This certificate expires on 2025-07-05.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for app.example.com to /etc/apache2/sites-available/000-default-le-ssl.conf
Congratulations! You have successfully enabled HTTPS on https://app.example.com

Test the automatic SSL renewal process:

Console
$ sudo certbot renew --dry-run

Restart Apache to apply the SSL configuration:

Console
$ sudo systemctl restart apache2

Test the LAMP Stack Installation

Create a sample table in the existing content_database database to display “Hello World! Greetings from centron” via a PHP application.

Log in to MySQL as dbadmin

Console
$ mysql -u dbadmin -p

Enter the password for the dbadmin user when prompted.

Switch to the sample database

Code
mysql> USE content_database;

Create the messages table

Code
mysql> CREATE TABLE IF NOT EXISTS messages (
       content_id INT AUTO_INCREMENT PRIMARY KEY,
       content VARCHAR(255) NOT NULL
      );

This table includes:

  • content_id: Auto-incrementing primary key
  • content: Text column for up to 255 characters

Insert a sample row

Code
mysql> INSERT INTO messages (content) VALUES ('Hello World! Greetings from centron');

View the table data

Code
mysql> SELECT * from messages;

Sample output:

Code
+----+------------------------------------------+
| content_id | content                           |
+------------+-----------------------------------+
|  1         | Hello World! Greetings from centron|
+------------+-----------------------------------+
1 row in set (0.00 sec)

Exit the MySQL console

Code
mysql> EXIT;

Create a sample PHP application

Create the setup.php file in your web root directory:

Console
$ sudo nano /var/www/html/app.example.com/setup.php

Add the following code:

<?php

$hostname = "localhost";

$username = "dbadmin";

$password = "Strong@@password123";

$dbname = "content_database";

// Establish Connection

$conn = new mysqli($hostname, $username, $password, $dbname);

// Check connection

if ($conn->connect_error) {

die("Connection Failed: " . $conn->connect_error);

}

$sql = "SELECT content FROM messages";

$result = $conn->query($sql);

if ($result && $result->num_rows > 0) {

$row = $result->fetch_assoc();

echo "

"

. htmlspecialchars($row["content"]) . "

";

} else {

echo "

No records found.

";

}

$conn->close();

?>

Code

This script connects to the content_database and retrieves data from the messages table. If no records are found, it displays “No records found.” If the database connection fails, it shows a connection error.

Set directory permissions

Console
$ sudo chown -R www-data:www-data /var/www/html/app.example.com/

Open your domain in a browser (for example https://app.example.com/setup.php) to confirm that the PHP application displays “Hello World! Greetings from centron”.

Conclusion

You have successfully installed and configured Apache, MySQL, and PHP (LAMP stack) on Ubuntu 20.04. You also created sample dynamic applications to test the integration of all components and ensured the server runs securely.

Jetzt 200 € Guthaben sichern

Testen Sie Ihr Setup auf ccloud³

Registrieren Sie sich in der ccloud³ und erhalten Sie 200 € Startguthaben für Ihr Projekt – z. B. für eine PostgreSQL-VM mit automatischen Backups.

centron Redaktion Technische Redaktion

Das Redaktionsteam von centron schreibt Anleitungen aus dem Betriebsalltag: getestet auf unserer eigenen Plattform, betrieben im Rechenzentrum in Hallstadt bei Bamberg.

Kategorie Ubuntu
Teilen
Noch offene Fragen?

Unser Team hilft Ihnen bei Ihrem konkreten Setup weiter – von Menschen, die die Plattform selbst betreiben.

War dieses Tutorial hilfreich?

Ihre Antwort wird anonym gespeichert und hilft uns, die Tutorials zu verbessern.

Kommentare

Noch keine Kommentare – stellen Sie die erste Frage zu diesem Tutorial.

Zum Kommentieren anmelden

Kommentare stehen centron-Kunden offen. Melden Sie sich in Ihrem Konto an, um eine Frage zu diesem Tutorial zu stellen.

Weiterlesen

Das könnte Sie auch interessieren

Jetzt kostenlos anfangen

Melden Sie sich an und erhalten Sie in den ersten 60 Tagen ein Guthaben von 200 € bei centron.

Dieses Werbeangebot gilt nur für neue Konten. Angebot ausschließlich für Gewerbetreibende.

Jetzt loslegen Sales kontaktieren