A LEMP stack refers to (L)inux, (E)Nginx, (M)ySQL, and (P)HP.

The following document is based on this DigitalOcean tutorial with minor and major improvements and further explanation for Ubuntu 18.04.


Ubuntu ships with ufw disabled by default. I recommend enabling it:

First, we allow the standard SSH port 22:

$ ufw allow 22/tcp

Then we enable ufw:

$ sudo ufw enable

At this point, ufw will only allow access to your system via the SSH port and nothing else. You should allow access for NGINX to be able to receive web connections.

Needless to say, if you have some other application firewall or a hardware one you will have to do it yourself.

Certbot requires an open HTTP port to be able to renew and issue your certificates, so allow port 80:

$ sudo ufw allow 80/tcp

Since we are going to do a LEMP stack, we also assume we will set-up HTTPS later, and so you should configure your firewall to allow HTTPS access to your server:

$ sudo ufw allow 443/tcp

I recommend opening the least number of ports you need for the outside world.


To install nginx execute:

$ sudo apt install nginx

You should now be able to reach your domain (or public IP) and see NGINX’s welcome page in HTTP.


MySQL is a database to store site or app data. It is vital in most situations. I.E: WordPress.

$ sudo apt install mysql-server

Once installed, we should execute the mysql_secure_installation command to edit security configurations within our MySQL installation.

In here you can:

  • Set a password for ROOT accounts.
  • Remove root accounts that are accessible from outside the localhost.
  • Remove anonymous user accounts
  • Remove the test database

Execute it with:

$ sudo mysql_secure_installation

The first thing which we will be asked is if we want to enable the VALIDATE PASSWORD plugin, it is safer to allow this and make sure to use strong passwords otherwise MySQL WILL REJECT WEAK PASSWORDS AND CAUSE PROBLEMS

The script will then ask what kind of requirements we want.

0 is ANY 8-character long passwords. 1 is ANY 8-character long passwords containing numbers, mixed case, and special characters. 2 is ANY 8-character long passwords containing numbers, mixed case, special characters, and dictionary words.

I recommend going with 1 because 2 is overkill and might cause problems later on.

Enter your root password when asked. Please avoid special characters like $ % and &.

After you’ve set the root password, you will be asked to confirm a set of options:

  • Remove anonymous users; this will remove and deny the creation of anonymous users from the database, allowing only valid users to log in to the database.

Confirm this setting.

  • Disallow remote login; this asks you if you will be making use of remote login on the root account, which is everything except login from localhost.

The most secure option for this is to disable it so we will reply with Y.. Unless you need to login remotely.

  • Remove and disable test database; this is not needed, so we will remove it.

The last question is if we want to reload the privilege tables, which will ensure that all of these settings we just changed will be loaded, so we will answer with Y.

auth_socket or native password

By default, MySQL will be installed and configured to let the root user access via the auth_socket plugin which authenticates a client from localhost using the Unix socket file SO_PEERCRED as explained here

When getsockopt is invoked with the SO_PEERCRED option, it accepts the struct ucred structure as a further parameter (cr). This structure has three elements: PID, uid, and gid. After calling getsockopt with a pointer to this structure, these fields will contain the process, user and group ids of the party on the other end of the socket connection.

And so will let the plugin know which user invoked an authentication command.

For example, this is what happens when you invoke login using sudo mysql so auth_socket will know that root invoked the command and will automatically log you inside the root user. While useful in several ways, such as scalability, utility, and security, it might generate errors for applications that try to automatically login inside the root account (phpMyAdmin).

Not that I recommend using the root account for everything, this is avoidable by giving each application its own user and password.

Since phpMyAdmin will not be able to use root credentials, it won’t be able to use this login schema, and every attempt will fail.

You have two possible solutions:

  1. You disable auth_socket and enable login via password for the root account using mysql_native_password.
  2. You create a specific phpMyAdmin account with any required privilege with a strong password for phpMyAdmin to use.

It depends on your workflow, but in this guide, I will disable auth_socket from root inside MySQL, and in doing so, we will lose access to the database using sudo mysql.

Disabling auth_socket in favour of mysql_native_password

Log in using sudo mysql and your LINUX root password.

Inside execute this query:

SELECT user,authentication_string,plugin,host FROM mysql.user;

This query will tell you what user is using which authentication method.

We can change how root will behave using the ALTER command as such:

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

password should be changed to a secure password of your choosing.

And finally, execute FLUSH PRIVILEGES; which will reload grant tables and apply changes.

From now on, you will only be able to access the root user of MySQL using the regular mysql -u root -p command.



The last part of a LEMP stack is PHP-FPM.

PHP-FPM is a module we can use with NGINX, and it stands for “fastCGI process manager.”

CGI scripts are a way to run a webserver when HTTP requests come, which are usually very slow.

So FastCGI is a much faster version of these processors, obviously in terms of PHP, PHP-FPM is then the “FastCGI” implementation of PHP, which can run with NGINX to handle PHP dynamic content generation much faster.

It is a deamon that can handle an incredible amount of PHP requests, even under heavy loads.

Installing PHP-FPM

Installing it is fairly easy:

sudo apt install php-fpm php-mysql

php-mysql is the backend helper handler of connections with your mysql database.

You might need to enable Ubuntu’s universe repository using sudo add-apt-repository universe. If you aren’t able to execute the command, then you need to install software-properties-common and then do a sudo apt update and try again.

NGINX will have no idea php-fpm is installed until you properly configure it for PHP requests inside your server/location blocks.

Thank you for reading.

Want to support me?

Find all information right here

You can also support me here:


  • My mom