How to install Linux, Apache, MySQL and PHP stack (LAMP) on Ubuntu 20.04

Introduction

A “LAMP” stack is a set of open source software applications that are typically installed together so that a server can host dynamic web sites and applications written in PHP. This term is actually an acronym that stands for the Linux operating system, with the Apache web server. Site data is stored in a MySQL database and dynamic content is processed using PHP.

In this guide, we will install a LAMP stack on an Ubuntu 20.04 server.

Step 1: Install Apache and update the firewall

The Apache web server is among the most popular in the world. It’s well documented, has an active user community, and has been widely used for much of the history of the web, making it a great default choice for hosting websites.

Install Apache using Ubuntu’s package manager, apt:

$ sudo apt update
$ sudo apt install apache2

If you are using sudo for the first time in this session, you will be prompted to provide your user password to confirm that you have the proper privileges to manage system packages with apt. You will also be prompted to confirm the Apache installation by pressing Y and ENTER.

Once the installation is complete, you will need to adjust your firewall settings to allow HTTP and HTTPS traffic. UFW has different application profiles that you can leverage to do this. To list all available UFW application profiles, you can run the following:

$ sudo ufw app list

You will see output like this:

Available applications:
  Apache
  Apache Full
  Apache Secure
  OpenSSH

Next, we explain each of these profiles:

Next, we explain each of these profiles:

  • Apache: this profile opens only port 80 (normal unencrypted web traffic).
  • Apache Full: This profile opens ports 80 (normal unencrypted web traffic) and 443 (encrypted TLS/SSL traffic).
  • Apache Secure: This profile opens only port 443 (encrypted TLS/SSL traffic).

For now, it is best to only allow connections on port 80, as this is a fresh installation of Apache and you do not have a TLS/SSL certificate configured to allow HTTPS traffic on your server yet.

To allow traffic only on port 80 use the Apache profile:

$ sudo ufw allow in "Apache"

You can verify the change with the following:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                                
Apache                     ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)                    
Apache (v6)                ALLOW       Anywhere (v6)     

Now, traffic is allowed on port 80 through the firewall.

You can run a quick check to check that everything went according to plan by going to your server’s public IP address in your web browser (see the note in the next section for your public IP address if you don’t have this information. ):

http://your_server_ip

You will see Apache’s default web page for Ubuntu 20.04, located there for informational and testing purposes.

How to find out the public IP address of your server

If you don’t know the public IP address of your server, there are several ways to find it. Usually this is the address that you use to connect to your server via SSH.

There are several ways to do it from the command line. First, you could use the iproute2 tools to get your IP address by typing this:

ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

This will give us two or three lines. All of these addresses are correct, but your computer can use one of them. Therefore, do not hesitate to try them all.

Step 2: Install MySQL

Now that you have a working web server, you will need to install a database system in order to store and manage your site data. MySQL is a popular database management system used in PHP environments.

Once again, use apt to purchase and install this software:

$ sudo apt install mysql-server

When prompted, confirm the installation by typing Y and then ENTER.

When the installation is complete, it is recommended to run a security script that comes pre-installed in MySQL. This script will remove some unsafe defaults and block access to your database system. Start the interactive script by running the following:

sudo mysql_secure_installation

You will be asked if you want to configure the VALIDATE PASSWORD PLUGIN.

Note: Enabling this feature is at the discretion of the user. If enabled, MySQL will reject passwords that do not match the specified criteria with an error message. Leaving validation disabled will be a safe option, but you should always use strong and unique passwords for database credentials.

Choose Y to indicate yes, or anything else to continue without enabling.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No:

If you answer “yes”, you will be prompted to select a password validation level. Note that if you enter 2 for the most secure level, you will receive error messages when trying to set any password that does not contain numbers, uppercase and lowercase letters, and special characters, or that is based on common words from the dictionary.

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1

Regardless of whether you have chosen to install the VALIDATE PASSWORD PLUGIN, your server will then prompt you to select and confirm a password for the MySQL root user. It should not be confused with the system root. The database root user is an administrative user with full privileges on the database system. Although the default MySQL root user authentication method does not require the use of a password, even if one is set, you will need to define a strong password at this point as an additional security measure. We will talk about this shortly.

If you have enabled password validation, you will be prompted for the password strength of the root user you just entered and your server will ask you if you want to continue using it. If you are satisfied with your current password, enter Y to indicate “yes” to the request:

Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y

For the rest of the questions, press Y and ENTER on each message. This will remove some anonymous users and the test database, the remote root login credentials will be disabled, and these new rules will be loaded for MySQL to immediately apply the changes you made.

When done, check if you can log into the MySQL console by typing the following:

$ sudo mysql

This will allow you to connect to the MySQL server as the root user of the administrative database, which is inferred from using sudo when executing this command. You should see the following output:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22
Server version: 8.0.19-0ubuntu5 (Ubuntu)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

To exit the MySQL console, type the following:

mysql> exit 

Note that you did not need to supply a password to log in as root user, even though you did define one when running the mysql_secure_installation script. This is because the default authentication method for the MySQL administrative user is unix_socket instead of password. While this may seem like a security issue initially, it makes the database server more secure because the only users who can log in as My SQL root user are system users with sudo privileges who connect from the console or through an application running with the same privileges. In practical terms, this means that you will not be able to use the root user of the administrative database to connect from your PHP application. Setting a password for the MySQL root account is a protection measure, in case the default authentication method is changed from unix_socket to password.

For added security, it is best to have dedicated user accounts with lower privileges configured for each database, especially if you plan to have multiple databases hosted on your server.

Note: At the time of this writing, MySQL’s native PHP library mysqlnd does not support caching_sha2_authentication, the default authentication method of MySQL 8. For this reason, when creating database users for PHP applications in MySQL 8, you will need to make sure they are configured to use mysql_native_password instead. We will demonstrate how to do it in step 5.

Now your MySQL server is installed and protected. Next, we will install PHP, the final component of the LAMP stack.

Step 3: Install PHP

It installed Apache to present its content and MySQL to store and manage its data. PHP is the component of our configuration that will process the code to display dynamic content to the end user. In addition to the php package, you will need php-mysql, a PHP module that allows it to communicate with MySQL-based databases. You will also need libapache2-mod-php to enable Apache to handle PHP files. The basic PHP packages will be installed automatically as dependencies.

To install these packages, run the following:

$ sudo apt install php libapache2-mod-php php-mysql

Once the installation is complete, you can run the following command to confirm your version of PHP:

$ php -v

And you would see an output like this:

PHP 7.4.3 (cli) (built: Feb 26 2021 14:24:23) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies

At this point, your LAMP stack is fully operational, but in order to test your setup with a PHP script, it is best to install a suitable Apache virtual host to store your website files and folders. We will do it in the next step.

Step 4: Create a virtual host for your website

Using the Apache web server, you can create virtual hosts (similar to server blocks in Nginx) to encapsulate configuration details and host more than one domain from a single server. In this guide, you will set up a domain called your_domain, but you will need to change this name to your own domain.

Ubuntu 20.04 has a default server block enabled, which is configured to provide documents from the /var/www/html directory. While this works well for a single site, it can be difficult to handle if you host multiple sites. Instead of modifying /var/www/html, we will create a directory structure within /var/www for your_domain site and leave /var/www/html set as the default directory that will be presented if a client request does not match any other site.

Create the directory for your_domain as follows:

$ sudo mkdir /var/www/your_domain

Next, you assign ownership of the directory with the $USER environment variable, which will refer to your current system user:

$ sudo chown -R $USER:$USER /var/www/your_domain

Then open a new configuration file in Apache’s sites-available directory using your preferred command line editor. In this case, we will use nano:

$ sudo nano /etc/apache2/sites-available/your_domain.conf

This will create a new blank file. Paste the following basic configuration:

<VirtualHost *:80>
    ServerName your_domain
    ServerAlias www.your_domain
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/your_domain
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

With this VirtualHost setting, we tell Apache to supply your_domain using /var/www/ your_domain as the web root directory. If you want to test Apache without a domain name, you can remove or comment out the ServerName and ServerAlias options by adding a # character to the beginning of the lines for each option.

Now, you can use a2ensite to enable the new virtual host:

$ sudo a2ensite your_domain

You may want to disable the default website that comes installed with Apache. This is necessary if a custom domain name is not used, as Apache’s default settings will overwrite your virtual host in this case. To disable the default Apache website, type the following:

$ sudo a2dissite 000-default

To ensure that your configuration file does not contain syntax errors, run the following:

$ sudo apache2ctl configtest

Finally, reload Apache for these changes to take effect:

$ sudo systemctl reload apache2

Now your new website is active, but the root web /var/www/your_domain directory is still empty. Create an index.html file in that location so that you can test that the virtual host works as expected:

$ nano /var/www/your_domain/index.html

Include the following content in this file:

<h1>Hello!</h1>

<p>This index page of <strong>your_domain</strong>.</p>

Now, head over to your browser and access your server’s domain name or IP address once more:

http://server_domain_or_IP

You should now see the page that you have created.

If you see this page, your Apache virtual host is working as expected.

You can leave this file set as a temporary landing page for your application until you configure an index.php file to replace it. When you do, remember to remove the index.html file from your document root, or rename it, as it would take precedence over a default index.php file.

Note on DirectoryIndex in Apache

With Apache’s default DirectoryIndex configuration, a file named index.html will always take precedence over an index.php file. This is useful for setting up maintenance pages in PHP applications, since a temporary index.html file can be created that contains an informational message for visitors. Since this page will take precedence over the index.php page, it will become the landing page of the application. Once maintenance is complete, the index.html file is removed from the document root, or renamed, to display the normal application page again.

If you want to change this behavior, you will need to edit the /etc/apache2/mods-enabled/dir.conf file and modify the order in which the index.php file is listed in the DirectoryIndex directive:

$ sudo nano /etc/apache2/mods-enabled/dir.conf
<IfModule mod_dir.c>
        DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
</IfModule>

After saving and closing the file, you will need to reload Apache for the changes to take effect:

$ sudo systemctl reload apache2

In the next step, we will create a PHP script to test that PHP is properly installed and configured on your server.

Step 4: Test PHP processing on your web server

Now that you have a custom location to host your website files and folders, we will create a test PHP script to verify that Apache can handle requests and process PHP file requests.

Create a new file called info.php inside your custom web root folder:

nano /var/www/your_domain/info.php

This will open an empty file. Add the following text, which is valid PHP code, inside the file:

<?php
phpinfo();

When done, save and close the file.

To test this script, go to your web browser and access the domain name or IP address of your server, followed by the name of the script, which in this case is info.php:

http://server_domain_or_IP/info.php

This page provides basic information about your server from a PHP perspective. It is useful for debugging and to make sure your settings are applied correctly.

If you can see this page in your browser, your PHP installation is working as expected.

After checking the relevant information about your PHP server through that page, it is recommended that you delete the file you created as it contains sensitive information about your PHP environment and your Ubuntu server. You can use rm to do it:

$ sudo rm /var/www/your_domain/info.php

You can always recreate this page if you need to access the information later.

Step 5: Test the connection to the database from PHP (optional)

If you want to test whether PHP can connect to MySQL and run database queries, you can create a test table with dummy data and query its content with a PHP script. In order to do this, we must create a test database and a new MySQL user properly configured to access it.

At the time of writing, MySQL’s native PHP library mysqlnd does not support caching_sha2_authentication, the default MySQL 8 authentication method. We will need to create a new user with the mysql_native_password authentication method in order to connect to the database. MySQL data from PHP.

We will create a database named example_database and a user named example_user, but you can substitute these names for different values.

First, connect to the MySQL console using the root account:

$ sudo mysql

To create a new database, run the following command from your MySQL console:

mysql> CREATE DATABASE example_database;

You can now create a new user and grant them full privileges on the custom database you just created.

The following command creates a new user named example_user, which uses mysql_native_password as the default authentication method. We define the password of this user as password, but you must replace this value with a strong password of your choice.

CREATE USER 'example_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';

Now, we must give this user permission to the example_database database:

mysql> GRANT ALL ON example_database.* TO 'example_user'@'%';

This will give the user example_user full privileges on the database example_database and at the same time will prevent this user from creating or modifying other databases on your server.

Now, close the MySQL shell with the following:

mysql> exit

You can check if the new user has the proper permissions by logging back into the MySQL console, this time with custom user credentials:

mysql -u example_user -p

Notice the -p flag in this command, which prompts you for the password that you used when you created the example_user user. After logging in to the MySQL console, confirm that you have access to the example_database database:

mysql> SHOW DATABASES;

This will generate the following result:

+--------------------+
| Database           |
+--------------------+
| example_database   |
| information_schema |
+--------------------+
2 rows in set (0.000 sec)

Next, we will create a test table called todo: From the MySQL console, run the following statement:

    CREATE TABLE example_database.todo (
        id INT AUTO_INCREMENT,
        body VARCHAR(255),
        PRIMARY KEY(id)
    );

Insert some rows of content into the test table. You may want to repeat the following command a few times, using different values:

mysql> INSERT INTO example_database.todo (body) VALUES ("My first item");

To confirm that the data was successfully saved to your table, run the following:

mysql> SELECT * FROM example_database.todo_list;

You will see the following output:

+---------+--------------------------+
| item_id | content                  |
+---------+--------------------------+
|       1 | My first item            |
|       2 | My second item           |
|       3 | My third  item           |
+---------+--------------------------+
4 rows in set (0.000 sec)

After confirming that there is valid data in your test table, you can close the MySQL console:

mysql> exit

Now you can create a PHP script that connects to MySQL and queries related to its content. Create a new PHP file in your custom web root directory using your preferred editor. In this case, we will use nano:

nano /var/www/your_domain/todo.php

The following PHP script establishes connection to the MySQL database, performs queries related to the contents of the todo table and displays the results in a list. If there is a problem with the database connection, it will throw an exception. Copy this content into your todo.php script:

<?php
$user = "example_user";
$password = "password";
$database = "example_database";todo.php 
$table = "todo";

try {
  $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
  echo "<h2>TODO</h2><ol>";
  foreach($db->query("SELECT body FROM $table") as $row) {
    echo "<li>" . $row['body'] . "</li>";
  }
  echo "</ol>";
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}

Save and close the file when editing is complete.

Now, you can access this page in your web browser by visiting your website’s domain name or public IP address followed by /todo.php:

http://your_domain/todo.php

You should see the page you have created in PHP with the list of items.

Conclusion

In this guide, we create a flexible basis for presenting PHP web sites and applications to your visitors using Apache as the web server and MySQL as the database system.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top