Having trouble installing the LEMP stack on your system? Don’t worry; we got you covered. This tutorial will go through the steps needed to set up LEMP on your Ubuntu server.

LEMP combines software to serve dynamic web pages and web applications. LEMP is an acronym for:

  • A Linux operating system
  • Nginx (Engine X) webserver
  • MySQL database
  • PHP

The backend will be stored in the MySQL database, and the dynamic processing will be handled through PHP. This tutorial will go through the steps to set it up on Ubuntu 18.04.

Note: The following steps will be the same if you want to set it up on Ubuntu 20.04.


Before we go ahead with the tutorial, you will need to have the following:

  1. A regular non-root user account with Sudo privileges
  2. A basic understanding of bash programming commands
  3. An Ubuntu 18.04 system (or Ubuntu 20.04)

Now that we have already acquired the needed things let’s go ahead and start setting LEMP on your system.

Step 1: Update the system

First, ensure that all your system packages are up-to-date by running the following apt-get commands in the terminal.

apt-get update

apt-get upgrade

To avoid any conflicts with your system, we would recommend removing other web servers on the system, like Apache2. If you have other web servers, remove them before going through the rest of the guide. To uninstall Apache2, you can run the following commands:

sudo service apache2 stop

sudo apt-get remove --purge apache2 apache2-utils apache2.2-bin apache2-common -y

sudo apt-get autoremove -y

sudo apt-get autoclean –y

Step 2: Install the Nginx webserver

We will use the Nginx web server to display web pages, which is modern and efficient. All the software used in this process will be taken directly from Ubuntu’s default repository.

sudo apt install nginx

From Ubuntu 18.04 onwards, Nginx is configured to start running once the installation is finished. If you have the ufw firewall enabled on your system (recommended), let’s go ahead and allow the connections to Nginx.

With the following command, you will allow regular HTTP traffic through port 80 since you haven’t configured an SSL certificate for your server. To enable this:

sudo ufw allow 'Nginx HTTP'

To check the changes, enter:

sudo ufw status

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

Now your server is up through the firewall ruleset in place. You can test if the server is up and running by accessing your server’s domain name or the public IP address through your web browser.

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:

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

Try each of them from the list of IP addresses through your web browser until you find your server’s public IP address. Once you have the IP address, enter the following code. If you installed Nginx properly, you would see a page similar to the picture below.

Step 3 – Installing MySQL Database

Now that we have set the webserver, we will install a database management system, MYSQL, to store and manage your website's data.

Install MySQL by entering:

sudo apt install mysql-server

This will install MySQL database software, but it’s not configured properly. Let’s go ahead and set the configurations. MySQL comes with a script asking whether we want to modify some insecure defaults. Initiate the script by typing:

sudo mysql_secure_installation

NOTE: When this feature is enabled, the passwords which don’t match the specified criteria will be rejected by MySQL. This will cause issues if you use a weak password with software that 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, unique passwords for database credentials.

To enable this script, press Y or anything else to continue without enabling the security feature. The output will look like this:

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:

Now you will need to select a level of password validation from 0, 1 and 2. Select the security settings that you wish to have on your server. The output looks like this (we picked 1):

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

Now enter and confirm the root password for the MySQL system. Once the password is in place, press y and hit ENTER to continue. This will remove some anonymous users and the test database, disable remote root logins, and load these new rules so that MySQL immediately respects our changes.

In Ubuntu systems running MySQL 5.7 (or newer), the root MySQL user is set to authenticate using the auth_socket plugin rather than with a password. This allows higher security and usability, but it complicates things when you request external programs to access the user (like phpMyAdmin).

If you use the auth_socket to access MySQL files, you can proceed to set up PHP. However, we will need to change some configurations if you want to use a password. To do this, open up MySQL from the terminal:

sudo mysql

Now check which authentication method each of your MySQL user accounts uses by:

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)

As you see above, the root user is using the auth_socket plugin. Configure the root account using the following command. Be sure to change the password with a strong password of your choosing.

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

Now the password is set, let's go ahead and reload the grant tables and put the changes in the system. Enter:


Done! Don’t take our word for it; let’s go ahead and check for yourself by entering the following command.

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)

As you see above, the authentication was changed. Now exit the MySQL shell by entering:


NOTE: Once the configure your 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:

mysql -u root -p

Congratulations, you have successfully set up your database system, and you can move on to installing PHP.

Step 4 – Installing PHP

We are almost done with Nginx to serve your pages and MySQL to manage your data. The last part is to generate dynamic content, which can be done using PHP. 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 the php-fpm module with an additional helper package, php-mysql, which will allow PHP to communicate with your database backend.

sudo apt install php-fpm php-mysql

If the above command does not work, you should add Ubuntu’s Universe repository first and then try the command again. To add the universe repository:

sudo add-apt-repository universe

You have all the required LEMP stack components installed. Pat yourself on the back for making it so far. However, we are still not done yet. We need to make some configurations to tell Nginx to use the PHP processor for dynamic content.

To do this, open a new server block configuration file within the /etc/nginx/sites-available/ directory. For this tutorial, we will use a filename called test.com, although you can name yours with anything you want.

sudo nano /etc/nginx/sites-available/test.com

The reason for creating a new server configuration file is that if something happens, you can easily restore the default configuration file without a hassle.

Copy and paste the following content on the file. Remember to change the server name to your own.

server {
       listen 80;
       root /var/www/html;
       index index.php index.html index.htm index.nginx-debian.html;
       server_name test.com;
       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;

So let me give a small explanation of the text that was just pasted on the configuration file:

  • 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 instead of test.com.
  • 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 find their way into the document root, they will not be served to visitors.

Once the data is set in place, save and close the file. Now enable the new server block by:

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

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

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

NOTE: To restore to the default configurations, simply make the symbolic link as follows:

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

Before continuing, we should check for syntax errors. If you get any errors, check the file before continuing forward:

sudo nginx –t

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

sudo systemctl reload nginx

You have successfully set up the configuration of your LEMP stack. However, it’s prudent to confirm that all of the components can communicate with one another.

Step 5 – Test all Configurations

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

Now in the created file, enter the following lines of code, which will return the information about your server:


Once the file is saved and closed, visit the newly created page through your web browser. You can do this by entering your server domain or IP address:


If you see a page similar to the one above, you have successfully set up PHP processing with Nginx. After verifying that Nginx renders the page correctly, removing the file you created is best, as it can 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.

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

Final words

A LEMP stack is a powerful platform that will allow you to set up and serve nearly any website or application from your Ubuntu server. Once LEMP is set up on the server, you can do many things, like setting up secure connections to the server using an SSL and others.

Once the basic structure is set, it’s easy to build your add-ons.

People also read: