Ubuntu 20.04 LTS: Guide To Installing LEMP Stack With Linux, Nginx, MySQL & PHP

Ubuntu 20.04 LTS

Ubuntu 20.04 LTS is the latest offering of Ubuntu. It was released on 23rd April 2020.

It has a number of important features, with emphasis on security and performance.

The official blog outlines all the features of Ubuntu 20.04 LTS.

Goal: Set up a fully functional LEMP stack with linux, nginx, MySQL & PHP to host our website(s)

(1) Deploy new server

I chose Vultr to deploy a new server (affiliate link).

Its servers are fast and responsive. The price is also rock-bottom.

I chose a server in Singapore since it has the lowest latency (ping) to where the bulk of my visitors are located.

LEMP Stack

If you click the Deploy Now button, within a few minutes, an email arrives stating that the server is ready for use.

(2) Install Nginx

The essential criteria to set up a web server is to install either Apache or Nginx.

According to experts, Nginx is better than Apache.

It is lighter, has less load and is able to serve pages faster to visitors.

So, we can install Nginx on Ubuntu with the following commands in Putty.

sudo apt update 
sudo apt install nginx 

Verify that Nginx is installed by going to the IP Address of the VPS:

Nginx LEMP Stack

(2) Install MySQL

MySQL stores the database of the server.

It can be installed with the commands:

sudo apt install mysql-server 


sudo mysql_secure_installation

You can choose the password for the root user and also remove the test database and disallow remote logins.

MySQL installation

Connect to MySQL

You can connect to the MySQL database and also create a Database with the commands

sudo mysql -uroot -p 

MySQL commands

(3) Install PHP

PHP, together with the necessary packages and support for MySQL, can be installed with the command:

sudo apt install php-fpm php-mysql

(5) Nginx will serve .php file as a download instead of executing it

At this stage, we can go to the default root web directory at /var/www/html to see whether php files are being executed.

cd /var/www/html

Create a php info file with the following command

nano phpinfo.php 

Paste the command

into the file and save it with a Ctrl X

Now, when you navigate to IP-Address/phpinfo.php, you will see that the file is not being executed but is being downloaded.

To rectify this, we have to open the default configuration file located at /etc/nginx/sites-available

nano /etc/nginx/sites-available/default 

The file, after the corrections, looks as follows:

# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
# This file will automatically load configuration files provided by other
# applications, such as Drupal or WordPress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.

# Default server configuration
server {
	listen 80 default_server;
	listen [::]:80 default_server;

	# SSL configuration
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.php index.html index.htm index.nginx-debian.html;

	server_name localhost;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;

	# pass PHP scripts to FastCGI server
	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass;
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;


	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#location ~ /\.ht {
	#	deny all;

# Virtual Host configuration for example.com
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#server {
#	listen 80;
#	listen [::]:80;
#	server_name example.com;
#	root /var/www/example.com;
#	index index.html;
#	location / {
#		try_files $uri $uri/ =404;
#	}

The changes I made are to add index.php to the list of file types.

I also uncommented the php location directive:

location ~ \.php$ {
		include snippets/fastcgi-php.conf; 

I commented out the line

# fastcgi_pass; 

and added the line

fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; 

Save the file and check for errors with the command

sudo nginx -t 

The error will be described. Rectify it and you will get the message that the test is successful.

Restart Nginx with the command

service nginx restart 

nginx command

Now, when you access the phpinfo.php file, it should work and you will get the following, indicating that everything is working perfectly:

phpinfo file

(4) Create a server block (virtual host)

Now, we can create as many server blocks as we need to host each of our websites.

(i) Create the directory to hold the files

mkdir /var/www/name-of-domain 

(ii) Create a configuration file with the command

sudo nano /etc/nginx/sites-available/name-of-domain 

Paste the same directives as in the default file into this file, with the necessary modifications to reflect the domain name

server {
    listen 80;
    server_name name-of-domain www.name-of-domain;
    root /var/www/name-of-domain;

    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;


(iv) Enable the server block with the command

sudo ln -s /etc/nginx/sites-available/name-of-domain /etc/nginx/sites-enabled/ 

Check the configuration file for errors with the command

sudo nginx -t 

and restart nginx if you get the all-clear sign

service nginx restart 

Point the domain to the IP Address

Now, go to the registrar with whom you have registered the domain (e.g. namecheap, godaddy etc) and enter the IP Address in the ‘A Record’ field.

Domain Namecheap

You can upload all of the website files into the domain folder.

Once the change propagates over the internet (it may take anywhere from a few minutes to a few hours depending on the ISP’s cache etc), you will be able to access the domain from the newly created server.

Leave a Reply

Your email address will not be published. Required fields are marked *