The LEMP software stack is a group of software that can be used to serve dynamic web pages/applications. This is an acronym that describes a Linux operating system, with an Nginx (pronounced like “Engine-X”) web server. The backend data is stored in the MySQL database and the dynamic processing is handled by PHP.

This guide demonstrates how to install a LEMP stack on an Ubuntu 18.04 server. The Ubuntu operating system takes care of the first requirement. We will describe how to get the rest of the components up and running.


Before you complete this tutorial, you should have a regular, non-root user account on your server with sudo privileges.

Once you have your user available, you are ready to begin the steps outlined in this guide.

Step 1 - Installing the Nginx Web Server

In order to display web pages to our site visitors, we are going to employ Nginx, a modern and efficient web server.

All of the software used in this procedure will come from Ubuntu's default package repositories (apt). You can check a more complete installation of it in the following article in How to Install Nginx on Ubuntu 18.04

Since this is our first time using apt for this session, start off by updating your server’s package index. Following that, install the server:


sudo apt update && apt upgrade -y sudo apt install nginx -y

On Ubuntu 18.04, Nginx is configured to start running upon installation.

If you do not have a domain name pointed at your server and you do not know your server's public IP address, you can find it by running the following command on shell:

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

This will print a two IP addresses: IPV4 ( and IPV6 (2001:DB8::/323). You can try, preferably, a IPV4 IP in turn in your web browser.

As an alternative, you can check which IP address is accessible, as viewed from other locations on the internet:

sudo curl -4

Type the address that you receive in your web browser and it will take you to Nginx's default landing page:

server_domain_or_IP Nginx Default Web Page

If you see the above page, you have successfully installed Nginx.

Step 2 - Installing MySQL to Manage Site Data

Now that you have a web server, you need to install MySQL (a database management system) to store and manage the data for your site.

Install MySQL by typing:


sudo apt install mysql-server-5.7 -y

The MySQL database software is now installed, but its configuration is not yet complete.

To secure the installation, MySQL comes with a script that will ask whether we want to modify some insecure defaults. Initiate the script by typing:


sudo mysql_secure_installation

This script will ask you to supply a password for use within the MySQL system. After this, it will ask if you want to configure the VALIDATE PASSWORD PLUGIN,

Warning: Enabling this feature is something of a judgment call. If enabled, passwords which don't match the specified criteria will be rejected by MySQL with an error. This will cause issues if you use a weak password in conjunction with software which automatically configures MySQL user credentials, such as the Ubuntu packages for phpMyAdmin. It is safe to leave validation disabled, but you should always use strong and unique passwords for database credentials.

Answer Y for 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've enabled validation with Yes, the script will also ask you to select a level of password validation. Keep in mind that if you enter 2 (for the strongest level) you will receive errors when attempting to set any password which does not contain numbers, upper and lowercase letters, and special characters, or which is based on common dictionary words.

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

If you enabled password validation, you'll be shown a password strength for the existing root password, and asked you if you want to change that password. If you are OK with your current password, enter N for "no" at the prompt:

Using existing password for root. Estimated strength of the password: 100 Change the password for root ? (Press y|Y for Yes, any other key for No): N

For the rest of the questions, you should press Y and hit the ENTER key at each prompt. This will remove some anonymous user, test database, disable remote root login and load these new rules so that MySQL immediately respects the changes we have made. At this point, your database system is now set up and you can move on to installing PHP.

Note that in Ubuntu systems running MySQL 5.7 (and later versions), the root MySQL user is set to authenticate using the auth_socket plugin by default rather than with a password. This allows for some greater security and usability in many cases, but it can also complicate things when you need to allow an external program (e.g., phpMyAdmin) to access the user.

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.

To do this, open up the MySQL prompt from your terminal:


sudo mysql

Next, 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 | *THISISNOTAVALIDPASSWORDTHATERE | mysql_native_password | localhost | | mysql.sys | *THISISNOTAVALIDPACANBEUSEDHERE | mysql_native_password | localhost | | debian-sys-maint | *CC744277A401A7DSW17BF607F876FF | mysql_native_password | localhost | +------------------+-------------------------------------------+-------------------------+

4 rows in set (0.00 sec) ::

In this example, you can see that the root user does in fact authenticate using the auth_socket plugin. To configure the root account to authenticate with a password, run the following ALTER USER command. Be sure to change password to a strong password of your choosing:


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

Then, run:



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 | +------------------+-------------------------------------------+-----------------------+-----------+

You can see in this example output that the root MySQL user now authenticates using a password. Once you confirm this on your own server, you can exit the MySQL shell:



At this point, your database system is now set up and you can move on to installing PHP.

Step 3 - Installing PHP for Processing

You now have Nginx installed to serve your pages and MySQL installed to store and manage your data. However, you still don't have anything that can generate dynamic content. This is where PHP comes into play.

Since Nginx does not contain native PHP processing like some other web servers, you will need to install php-fpm, which stands for "fastCGI process manager". We will tell Nginx to pass PHP requests to this software for processing.

Install this module along with an additional helper package that will allow PHP to communicate with your database backend. The installation will pull in the necessary PHP core files. Do this by typing:


sudo apt install php-fpm php-mysql -y

You now have your PHP components installed, but you need to make a slight configuration change to make your setup more secure.

Open the main php-fpm configuration file with root privileges:


sudo nano /etc/php/7.2/fpm/php.ini

In this file, find the parameter that sets cgi.fix_pathinfo. This will be commented out with a semicolon (;) and set to "1" by default.

This is an extremely insecure setting because it tells PHP to attempt to execute the closest file it can find if the requested PHP file cannot be found. This could allow users to craft PHP requests in a way that would allow them to execute scripts that they shouldn't be allowed to execute.

Change both of these conditions by uncommenting the line and setting it to "0", like this:

cgi.fix_pathinfo = 0

Save and close the file when you are finished. Then, restart your PHP processor by typing:


sudo systemctl restart php7.2-fpm

This will implement the change that you have made.

Step 4 - Configuring Nginx to Use the PHP Processor

Presently, you have all of the required components installed. The only configuration change you still need to make is to tell Nginx to use the PHP processor for dynamic content.

This is done on the server block level (server blocks are similar to Apache's virtual hosts). Open the default Nginx server block configuration file by typing:


sudo nano /etc/nginx/sites-available/default

Currently, with the comments removed, the Nginx default server block file looks like this:

server { listen 80 default_server; listen [::]:80 default_server;

server_name _; root /var/www/html; index index.html index.htm index.nginx-debian.html;

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

There are several changes you need to make to this server block:

  • First, add ==index.php== as the first value of the ==index== directive so that files named ==index.php== are served, if available, when a directory is requested

  • Modify the ==server_name== directive to point to your server's domain name or public IP address.
    • For the actual PHP processing, uncomment a segment of the file that handles PHP requests by removing the pound symbols (#) from in front of each line. This will be the ==location ~.php$== location block, the included fastcgi-php.conf snippet, and the socket associated with ==php-fpm==.

    • Additionally, uncomment the location block dealing with ==.htaccess== files using the same method. Nginx doesn't process these files. If any of these files happen to find their way into the document root, they should not be served to visitors.

The changes that must be made are highlighted in the text below:

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

server_name your_server_domain_or_IP;

location / { try_files $uri $uri/ =404; } location ~ .php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } location ~ /.ht { deny all; } }

Lastly, there may be a discrepancy between the file referenced by the fastcgi_pass directive within the location ~ .php$ block. You must ensure that the name of this file aligns with what is actually stored in the /run/php directory on your server.

To check this, save the file and close the text editor, then run the following command:


ls /run/php/

In this example, you can see that the file in question is actually, not php7.2-fpm.sock, which is what’s listed in the location ~ .php$ directive. If there’s a similar inconsistency on your machine, open up the /etc/nginx/sites-available/default file once more and update the fastcgi_pass directive:


sudo nano /etc/nginx/sites-available/default

location ~ .php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/; }

Again, save and close the file. Then, test your 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.

Step 5 - Creating a PHP File to Test Configuration

Your LEMP stack should now be completely set up. You can test it to validate that Nginx can correctly hand .php files off to the PHP processor.

To do this, use your text editor to create a test PHP file called info.php in your document root:


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

Enter the following lines into the new file. This is valid PHP code that will return information about your server:

<?php phpinfo();?>

When you are finished, save and close the file.

Now, you can visit this page in your web browser by visiting your server's domain name or public IP address followed by /info.php:


You should see a web page that has been generated by PHP with information about your server:


If you see a page that looks like this, you've set up PHP processing with Nginx successfully.

After verifying that Nginx renders the page correctly, it's best to remove the file you created as it can actually give unauthorized users some hints about your configuration that may help them try to break in. You can always regenerate this file if you need it later.

For now, remove the file by typing:


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

With that, you now have a fully-configured and functioning LEMP stack on your Ubuntu 18.04 server.


A LEMP stack is a powerful platform that will allow you to set up and serve nearly any website or application from your server.

There are a number of next steps you could take from here. For example, you should ensure that connections to your server are secured. To this end, you could secure your Nginx installation with Let’s Encrypt. By following this guide, you will acquire a free TLS/SSL certificate for your server, allowing it to serve content over HTTPS.

Read more about: MySQLUbuntu