In this guide, we will install LEMP stack on Ubuntu 18.04 server.

To Install LAMP stack

1. Installing Nginx Web Server

The Nginx web server is the most popular web servers in the world. It’s active community and detailed documentation eventually makes it a great choice for hosting a website.

Install Nginx using ( Advanced Package Tool ) apt:

Start off by updating your server’s package index:

sudo apt update
sudo apt install nginx

Nginx registers itself with ufw upon installation

It is recommended that you enable the most restrictive profile that will still allow the traffic you want. Since you haven’t configured SSL for your server in this guide, you will only need to allow traffic on port 80.

To enable this type:

sudo ufw allow 'Nginx HTTP'

To verify the changes type:

sudo ufw status

sudo ufw status command will show HTTP traffic allowed as follows:

OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Now installation of Nginx server is done. You can verify that by visiting your server’s public IP address in your web browser.

Nginx Default Page

2. Installing MySQL Database Server

Now that we have installed a web server, its time to install MySQL (a database management system) to store and manage the data for our site.

Install MySQL using ( Advanced Package Tool ) apt:

sudo apt install mysql-server

Along with the amount of disk space they’ll take up, this command will show you a list of the packages that will be installed. Enter Y to continue.

To secure the installation and modify insecure defaults, Initiate the following script:

sudo mysql_secure_installation

This script will ask if you want to configure the VALIDATE PASSWORD PLUGIN.

Note: Always use strong passwords for database credentials.

Type Y to enable, or any other key 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 enable by typing y, you’ll be prompted to select a password level by entering 0 or 1 or 2.

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

Next, you’ll be asked to submit and confirm a root password:

Please set the password for root here.

New password:

Re-enter new password:
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) :

For the rest of the questions, press Y and hit the ENTER key at each prompt.

If you prefer to use a password when connecting to MySQL as root, you will need to switch its authentication method from auth_socket to mysql_native_password.

sudo mysql

Now check which authentication method each of your MySQL user accounts use with the following command:

select user,authentication_string,plugin,host from mysql.user;
| user             | authentication_string                     | plugin                | host      |
| root             |                                           | auth_socket           | localhost |
| mysql.session    | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys        | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| debian-sys-maint | *CC744277A401A7D25BE1CA89AFF17BF607F876FF | mysql_native_password | localhost |
4 rows in set (0.00 sec)

We can observe that the root user authenticate using the auth_socket plugin. To modify the root user to authenticate with a password, run the following ALTER USER command. Be sure to change password to a strong password of your choice:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

Then, run FLUSH PRIVILEGES which tells the server to reload the grant tables and put your new changes into effect:


Check the authentication methods employed by each of your users again to confirm that root no longer authenticates using the auth_socket plugin:

SELECT user,authentication_string,plugin,host FROM mysql.user;
| user             | authentication_string                     | plugin                | host      |
| root             | *3636DACC8616D997782ADD0839F92C1571D6D78F | mysql_native_password | localhost |
| mysql.session    | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys        | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| debian-sys-maint | *CC744277A401A7D25BE1CA89AFF17BF607F876FF | mysql_native_password | localhost |
4 rows in set (0.00 sec)

You will be able to observe that the root MySQL user now authenticates using a password.

Now to exit from MySQL CLI use the following command.


After configuring root MySQL user to authenticate with a password, you’ll no longer be able to access MySQL with the sudo mysql command used previously. Instead, you must run the following:

sudo mysql -u root -p

Now enter the password you just set to navigate MySQL prompt.

3. Installing PHP and Modules

PHP is a server side scripting language which helps your code to communicate MySQL database and get information to display it on a web page or to enter given information into database.

Install PHP using ( Advanced Package Tool ) apt:

sudo apt install php-fpm php-mysql

In order to tell Nginx to use the PHP processor for dynamic content we need to make a few configuration changes on server block level (server blocks are similar to Apache’s virtual hosts).

sudo nano /etc/nginx/sites-available/

In this example, the new server block configuration file is named, although you can name yours whatever you’d like:

By editing a new server block configuration file, rather than editing the default one, you’ll be able to easily restore the default configuration if you ever need to.

server {
        listen 80;
        root /var/www/html;
        index index.php index.html index.htm index.nginx-debian.html;

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

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

        location ~ /\.ht {
                deny all;

Here’s what each of these directives and location blocks do:

  • listen â€” Defines what port Nginx will listen on. In this case, it will listen on port 80, the default port for HTTP.
  • root â€” Defines the document root where the files served by the website are stored.
  • index â€” Configures Nginx to prioritize serving files named index.php when an index file is requested, if they’re available.
  • server_name â€” Defines which server block should be used for a given request to your server. Point this directive to your server’s domain name or public IP address.
  • location / â€” The first location block includes a try_files directive, which checks for the existence of files matching a URI request. If Nginx cannot find the appropriate file, it will return a 404 error.
  • location ~ \.php$ â€” This location block handles the actual PHP processing by pointing Nginx to the fastcgi-php.conf configuration file and the php7.2-fpm.sock file, which declares what socket is associated with php-fpm.
  • location ~ /\.ht â€” The last location block deals with .htaccess files, which Nginx does not process. By adding the deny all directive, if any .htaccess files happen to find their way into the document root they will not be served to visitors.

After adding this content, save and close the file. Enable your new server block by creating a symbolic link from your new server block configuration file (in the /etc/nginx/sites-available/ directory) to the /etc/nginx/sites-enabled/ directory:

sudo ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

Then, unlink the default configuration file from the /sites-enabled/ directory:

sudo unlink /etc/nginx/sites-enabled/default

Note: If you ever need to restore the default configuration, you can do so by recreating the symbolic link, like this:

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/

Test your new configuration file for syntax errors by typing:

sudo nginx -t

If any errors are reported, go back and recheck your file before continuing.

When you are ready, reload Nginx to make the necessary changes:

sudo systemctl reload nginx

This concludes the installation and configuration of your LEMP stack. However, it’s prudent to confirm that all of the components can communicate with one another.

Now that you have a LEMP stack installed, to test that PHP is configured properly we will create a very basic PHP script called info.php

sudo nano /var/www/your_domain/info.php

This will open a blank file, Add the following valid PHP code:


At last save and close the file.

Now that we have saved a valid PHP code, we can look for a some basic information.

To try this out, visit this page in your web browser:


As a result, web page should look something like below:

PHP Info Page

As a result this page provides some basic information about your server from the perspective of PHP. In short it is useful for debugging and to ensure that your settings are being applied correctly.

Meanwhile it could actually give information about your server to unauthorized users, To block such activity we probably want to remove this file after this test.

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

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


Now that you have Installed LEMP STACK on Ubuntu 18.04, you can now host your website in the server. One of the popular thing you can do is install WordPress and design your own website or blog for your business.

Hope this tutorial is helpful and comment down if you have any query or issue.