The Complete Guide To Install LEMP Server(Ubuntu, Nginx, MySQL, PHP) Using Ubuntu 20.04 LTS
The Complete Guide To Install LEMP Server(Ubuntu, Nginx, MySQL, PHP) Using Ubuntu 20.04 LTS
June 18, 2020

This tutorial provides the steps required to install LEMP Stack using Ubuntu 20.04 LTS server as listed below. The steps should be the same or similar on other versions of Ubuntu and Linux systems.

Linux - Ubuntu 20.04

Nginx - Nginx 1.17

MySQL - MySQL 8

PHP - PHP 7.4

phpMyAdmin

Prerequisites

This tutorial assumes that you have already completed the installation of the Ubuntu 20.04 LTS server on your preferred service provider. It also assumes that the standard web server ports 80 and 443 are publicly accessible. The popular service providers include AWS, Linode, Digital Ocean, UpCloud, Vultr, etc. You can also follow the below-listed tutorials to spin up Ubuntu 20.04 LTS.

Install Nginx On Ubuntu 20.04 LTS

This section provides the steps to install Nginx 1.17 on Ubuntu 20.04 LTS. The commands required to install Nginx are shown below.

# Refresh the indexes
sudo apt update

# Install nginx
sudo apt install nginx

# Check and enable Nginx - Auto start
sudo systemctl is-enabled nginx
sudo systemctl enable nginx

# Check Nginx Version
nginx -v

# Output
nginx version: nginx/1.17.10 (Ubuntu)

# Check Nginx Status
sudo systemctl status nginx

# Output
nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2020-06-18 05:55:53 UTC; 24s ago Docs: man:nginx(8) Main PID: 2640 (nginx) Tasks: 3 (limit: 1119) Memory: 5.8M CGroup: /system.slice/nginx.service ├─2640 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; ├─2641 nginx: worker process └─2642 nginx: worker process
----
----

The above-mentioned commands installed Nginx 1.17.10 while writing this tutorial. The important configurations and directories of Nginx installed from the Ubuntu repositories are listed below.

  • Configurations Directory - /etc/nginx/conf.d - Additional server configurations. It's empty by default.
  • Modules Available Directory - /etc/nginx/modules-available - The directory to store the modules configurations.
  • Modules Enabled Directory - /etc/nginx/modules-available - The directory the symlinks of the modules configurations. The symlinks of image filter, xslt filter, mail, and stream modules are available by default.
  • Sites Available Directory - /etc/nginx/sites-available - The directory to store the server blocks. The default server block is available within this directory.
  • Sites Enabled Directory - /etc/nginx/sites-enabled - The directory having the symlinks of the server blocks available at /etc/nginx/sites-available. We can enable or disabled the server blocks available at /etc/nginx/sites-available by creating or deleting the symlinks. The symlink of the default server block is available within this directory.
  • Main Configuration - /etc/nginx/nginx.conf - The main configuration of Nginx. View it on GitHub.
  • Default Server Block - /etc/nginx/sites-available/default - The default server block. View it on GitHub.

The default www directory of Nginx is /var/www/html. It serves the static files from this directory using the default server block. Now open the Nginx's Home Page in your favorite browser by using the Server's public IP address or the DNS name assigned by the service provider. It should show the Home Page similar to Fig 1. It can also be accessed using http://localhost in case it's installed on a local desktop or server system.

Install LEMP Using Ubuntu 20.04 LTS - Nginx - Home

Fig 1

You can follow How To Install And Configure Nginx on Ubuntu 20.04 LTS for more details and Configure Virtual Host Or Server Block On Nginx to configure the websites for production usage. You can also follow How To Install Let's Encrypt For Nginx On Ubuntu and Redirect HTTP to HTTPS on Nginx to secure your websites using Let's Encrypt.

Install MySQL 8 On Ubuntu 20.04 LTS

This section provides the steps required to install MySQL 8 on Ubuntu 20.04 LTS. Now execute the below-mentioned command to install MySQL 8.

# Install MySQL Server 8
sudo apt install mysql-server

# MySQL Status
sudo systemctl status mysql

# Output
mysql.service - MySQL Community Server Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2020-06-18 05:57:29 UTC; 11s ago Main PID: 3468 (mysqld) Status: "Server is operational" Tasks: 39 (limit: 1119) Memory: 317.3M CGroup: /system.slice/mysql.service └─3468 /usr/sbin/mysqld
-----

It installs MySQL core, server, and client packages. Also, the MySQL server version 8.0.20 was installed while writing this tutorial. Configure and secure the installation using the command mysql_secure_installation as shown below. It will ask to set the root password and a few security questions.

Step 1 - Secure Installation - Execute the command to start the MySQL configuration.

# Secure MySQL
sudo mysql_secure_installation

Step 2 - Password Validator - It asks to confirm the usage of the password validator to validate the password. It will also show the password strength while providing the password.

# Password Validator Component
Press y|Y for Yes, any other key for No: y

If we select No, it won't check the password strength of the MySQL root and other users while adding them. We should use a strong password for the MySQL users, hence it's recommended to use the Password Validator Component.

Step 3 - Password Validation Level - The secure installation command asks the password validation level and provides options to choose among Low(0), Medium(1), and Strong(2). It's recommended to use at least Medium Level to have a strong password of all the MySQL users. The validation rules of all the levels are as listed below.

Low - It expects a password having at least 8 characters without any restriction on the characters.

Medium - The Medium Level expects a password that has at least 8 characters and allows numeric, uppercase, lowercase, and special characters.

Strong - The Strong Level expects a password that has at least 8 characters and allows numeric, uppercase, lowercase, and special characters. It also allows the dictionary file.

# Password Validation Level
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1

Step 4 - Root Password - The default authentication plugin used by MySQL for the root user is auth_socket.

# Password Prompt
New password:<password>
Re-enter new password:<repeat password>

In case you have selected to use Password Validator, it will also show the password strength of the root password and confirm to use the given password as shown below.

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

If we opt for No, it will again prompt for the password.

Step 5 - Remove Anonymous Users - After providing the password, the secure installation process asks to remove the anonymous users. MySQL adds an anonymous user while installing it for testing purposes and allows anyone to log in without a password. It's recommended to remove the anonymous user.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y

Step 6 - Disallow Remote Login - The secure installation process also asks to confirm whether remote login is allowed for the root user. We should choose option y to restrict the root user to the localhost. We can always add additional users to allow remote login when required.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y

Step 7 - Remove Test Database - MySQL creates the test database while installing it. You may keep the test database for analysis purposes and later drop it.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y

Step 8 - Reload Privilege Tables - At last, the secure installation asks to reload the privileges tables to immediately apply the changes.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y

Now we will change the password plugin of the root user to caching_sha2_password to allow the other applications including phpMyAdmin to login to MySQL server using the root user. You may skip this in case the root user is not required by other applications including phpMyAdmin.

# Login to MySQL
sudo mysql

# Check password scheme of root user
mysql> SELECT user,authentication_string,plugin,host FROM mysql.user;

# Note the password plugin of root user
+------------------+------------------------------------------------------------------------+-----------------------+-----------+
| user | authentication_string | plugin | host |
+------------------+------------------------------------------------------------------------+-----------------------+-----------+
| debian-sys-maint | $A$005$[DA
NP9|K1zAmHe`LVwrhII7zBo5b5xUoPnvOLuCa9CSJVqCn7W1rzOCCyZD | caching_sha2_password | localhost |
| mysql.infoschema | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | caching_sha2_password | localhost |
| mysql.session | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | caching_sha2_password | localhost |
| mysql.sys | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED | caching_sha2_password | localhost |
| root | | auth_socket | localhost |
+------------------+------------------------------------------------------------------------+-----------------------+-----------+

# Change the password plugin - caching_sha2_password
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '<pw>';

# Apply changes
mysql> flush privileges;

# Check password scheme of root user
mysql> SELECT user,authentication_string,plugin,host FROM mysql.user;

# Note the password plugin of root user
+------------------+-------------------------------------------+-----------------------+-----------+
| user | authentication_string | plugin | host |
+------------------+-------------------------------------------+-----------------------+-----------+
| root | $A$005$ZtYD-ppbn>iO�"MHhl/0TXh9Qo3xYdWK3ThKPmDB6r.QhVlZY1dcT1LWH0A | caching_sha2_password | localhost |
+------------------+-------------------------------------------+-----------------------+-----------+

# Quit Database
mysql> exit

Apart from changing the root user password plugin, we can also add additional users and databases as shown below.

# Login to MySQL
sudo mysql
# OR
mysql -u root -p

# Create Users
mysql> CREATE USER 'projecta'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'password';
mysql> CREATE USER 'projectb'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'password';

# Create Database - with default character set
mysql> CREATE DATABASE projecta;

# Create Database - with utf8mb4 character set - preferred
mysql> CREATE DATABASE projectb CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

# Grant privileges to the users
mysql> GRANT ALL PRIVILEGES ON projecta.* TO 'projecta'@'localhost';
mysql> GRANT ALL PRIVILEGES ON projectb.* TO 'projectb'@'localhost';

# Apply Changes
mysql> FLUSH PRIVILEGES;

# Exit MySQL
mysql> exit;

You can also follow How To Install MySQL 8 on Ubuntu 20.04 LTS to learn more about installing MySQL 8.

Install PHP 7.4 On Ubuntu 20.04 LTS

This section provides the steps to install PHP 7.4 on Ubuntu 20.04 LTS.

Nginx needs PHP FPM to process the PHP requests. Use the below-mentioned command to install PHP 7 only if required. It also installs the Apache Web Server which is not required as part of the LEMP stack.

# Install PHP - Install only if required - It also install Apache Web Server
sudo apt install php7.4

# Verify PHP
php --version

# Output
PHP 7.4.3 (cli) (built: May 26 2020 12:24:22) ( 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

We can install PHP 7 for LEMP stack on Ubuntu 20.04 LTS as shown below.

# Install PHP FPM - Required by Nginx
sudo apt install php7.4-fpm

# Check whether enabled on system boot
sudo systemctl is-enabled php7.4-fpm

# Output
enable

# Install MySQL Extension
sudo apt install php7.4-mysql

# Install CGI and CLI if not installed by default
sudo apt install php7.4-common php7.4-cgi php7.4-cli

# Install CURL and JSON extensions
sudo apt install php7.4-curl php7.4-json

# Install PHP GD and Imagick
sudo apt install php7.4-gd php-imagick

# Multibyte String, Internationalization and Spell Check
sudo apt install php7.4-mbstring php7.4-intl php7.4-pspell

# Multibyte String, Internationalization and Spell Check - Required for Wordpress Installation
sudo apt install php-mbstring php-intl php-pspell

# Emails
sudo apt install php7.4-imap

# Tidy and XML RPC
sudo apt install php7.4-tidy php7.4-xmlrpc

# Excel
sudo apt-get install php7.4-xsl

# Install OPcache extension
sudo apt-get install php7.4-opcache

# Install Zip
sudo apt-get install php7.4-zip

Also, make sure that PHP-FPM is active and running. It's required by Nginx to process the PHP requests.

PHP FPM Status
sudo systemctl status php7.4-fpm

# Output
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 Thu 2020-06-18 05:36:17 UTC; 24s ago Docs: man:php-fpm7.4(8) Process: 33932 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,> Main PID: 33919 (php-fpm7.4) Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec" Tasks: 3 (limit: 1119) Memory: 11.3M CGroup: /system.slice/php7.4-fpm.service ├─33919 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf) ├─33930 php-fpm: pool www └─33931 php-fpm: pool www
-----

Now configure the PHP INI file as shown below.

# Update PHP Configuration
sudo nano /etc/php/7.4/fpm/php.ini

# Update
cgi.fix_pathinfo=0

# Reload PHP FPM
sudo systemctl reload php7.4-fpm
# OR
# Restart PHP FPM
sudo systemctl restart php7.4-fpm

# Restart Nginx
sudo systemctl restart nginx

We can enable PHP for Nginx by disabling the default server block and adding the server block as shown below. Also, make sure to replace the example.com with your domain name.

# Disabled default server block
sudo unlink /etc/nginx/sites-enabled/default

# Create Server Block
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com

# Update Server Block
sudo nano /etc/nginx/sites-available/example.com

# Update Server Block
server {
listen 80;
server_name example.com; # Use localhost to access it on local system

root /var/www/example.com/html;

index index.html index.htm index.php;

location / {
try_files $uri $uri/ =404;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

location ~ /\.ht {
deny all;
}
}

# Save and exit the editor

# Create Symlink
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com

# Reload Nginx
sudo systemctl reload nginx

Now we will create our first PHP program and execute it to print PHP info.

# Create HTML directory
sudo mkdir -p /var/www/example.com/html

# Create Welcome File
sudo nano /var/www/example.com/html/index.php

# Content
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello LEMP</title>
</head>
<body>
<h1>LEMP Stack.</h1>
</body>
</html>

# Save and exit the editor

Now if you open the URL http://example.com or http://localhost using the Browser, it should show the welcome message - LEMP Stack. We will create another PHP file to print the PHP info as shown below.

# Create Info File
sudo nano /var/www/example.com/html/info.php

# Content
<?php
echo phpinfo();

# Save and exit the editor

Now open the PHP file using the URL http://example.com/info.php or http://localhost/info.php. It should show the output as shown in Fig 2.

Install LEMP Using Ubuntu 20.04 LTS - PHP - Info

Fig 2

Now remove the info.php for security purposes.

The above-mentioned commands install PHP 7.4 with the generic extensions required by most of the applications. You can also follow How To Install PHP For Nginx On Ubuntu 20.04 LTS to learn more about installing PHP 7 for Nginx.

Install phpMyAdmin On Ubuntu 20.04 LTS (Optional)

This section provides the steps required to install phpMyAdmin on Ubuntu 20.04 LTS. It's optional to install phpMyAdmin as part of the LEMP stack set up. The MySQL server can be accessed directly using the SSH. We can also access MySQL using PHPStorm and SQLYog using SSH and HTTP Tunneling.

Before we start installing phpMyAdmin, we must disable the Validate Password Plugin of MySQL as shown below.

# Login to MySQL

sudo mysql
# OR
mysql -u root -p

# Disabled Validate Password Plugin
mysql> UNINSTALL COMPONENT "file://component_validate_password";
mysql> exit;

Now start installing phpMyAdmin on Ubuntu by executing the commands as shown below.

# Install phpMyAdmin
sudo apt install phpmyadmin php-mbstring php-gd php-zip php-json

The installation process asks to choose the web server as shown in Fig 3.

Install LEMP Using Ubuntu 20.04 LTS - phpMyAdmin - Web Server

Fig 3

The install process asks to create the storage database of phpMyAdmin. You may either skip it or install it. In case you have opted to install the database by choosing Yes as shown in Fig 4, it will ask for the password and confirm password as shown in Fig 5 and Fig 6.

Install LEMP Using Ubuntu 20.04 LTS - phpMyAdmin - Database

Fig 4

Install LEMP Using Ubuntu 20.04 LTS - phpMyAdmin - Password

Fig 5

Install LEMP Using Ubuntu 20.04 LTS - phpMyAdmin - Confirm Password

Fig 6

This creates the database of phpMyAdmin and also completes the installation. We can use phpMyAdmin with and without its database. Now again enable the Validate Password Plugin as shown below.

# Login to MySQL

sudo mysql
# OR
mysql -u root -p

# Enable Validate Password Plugin
mysql> INSTALL COMPONENT "file://component_validate_password";
mysql> exit;

The installation process installs phpMyAdmin at /usr/share/phpmyadmin and generates the configuration files at /etc/phpmyadmin.

Now, enable the PHP module mbstring, configure phpMyAdmin as sub-directory, and reload the Nginx Web Server as shown below.

# Enable PHP module mbstring
sudo phpenmod mbstring

# Configure phpMyAdmin
sudo ln -s /usr/share/phpmyadmin /var/www/example.com/html/phpmyadmin
sudo chmod 775 -R /usr/share/phpmyadmin/
sudo chown root:www-data -R /usr/share/phpmyadmin/

# Reload Nginx
sudo systemctl reload nginx

The above-mentioned commands enable phpMyAdmin as a sub-domain to the primary domain using the alias phpmyadmin. We can access the same on the browser using the URLs as shown below.

Localhost - http://localhost/phpmyadmin OR http://127.0.0.1/phpmyadmin

Remote/Production Server - http://www.example.com/phpmyadmin OR http://xx.xx.xxx.xxx/phpmyadmin - Replace www.example.com with your server's domain address or xx.xx.xxx.xxx with your server's IP address.

Now secure the phpMyAdmin installation using the in-built security feature of Nginx Web Server i.e. Basic Authentication. After enabling the Basic Authentication, the browser will prompt for username and password to access the phpMyAdmin web interface. We can enable the Basic Authentication as shown below.

# Install Apache Utils
sudo apt install apache2-utils

# Configure phpMyAdmin - Update server block
sudo nano /etc/nginx/sites-available/example.com

# Update Server Block
server {
listen 80;
server_name example.com; # Use localhost to access it on local system

root /var/www/example.com/html;

index index.html index.htm index.php;

location / {
try_files $uri $uri/ =404;
}

location /phpmyadmin {
auth_basic "Restricted";
auth_basic_user_file /etc/phpmyadmin/.htpasswd;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

location ~ /\.ht {
deny all;
}
}

# Save and exit the editor

# Reload Nginx
sudo systemctl reload nginx

The server block with the basic auth configurations makes sure that the web interface of phpMyAdmin is accessible only if the valid username and password are specified in the auth user file i.e. .htpasswd file. We can add username and password to the .htpasswd as shown below.

# Make directory
sudo mkdir -p /etc/phpmyadmin

# Generate Username Password pair
sudo htpasswd -c /etc/phpmyadmin/.htpasswd username

# Output
New password:
Re-type new password:
Adding password for user username

We can add more users to the htpasswd file without using the -c argument. Now if we try to access phpMyAdmin, it will show a prompt asking for username and password.

Summary

This tutorial provided the steps required to install and set up the LEMP stack using Ubuntu 20.04 LTS, Nginx 1.17, MySQL 8, and PHP 7.4.

Write a Comment

Click on the captcha image to get new code.
Discussion Forum by DISQUS