The LEMP software stack is a group of software that can be used to serve dynamic web pages and web 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. Set up this account by completing our initial server setup guide for Ubuntu 18.04.
Once you have your user available, you are ready to begin the steps outlined in this guide.
In order to display web pages for your site visitors, you’re going to employ Nginx, a modern, efficient web server.
All of the software used in this procedure will come from Ubuntu’s default package repositories. This means you’ll use the apt
package management suite to complete the necessary installations.
Since this is your first time using apt
for this session, start off by updating your server’s package index:
Next, install the server:
On Ubuntu 18.04, Nginx is configured to start running upon installation.
If you have the ufw
firewall running, as outlined in the initial setup guide, you will need to allow connections to Nginx. Nginx registers itself with ufw
upon installation, so the procedure is rather straightforward.
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
.
Enable this by typing the following:
You can verify the change by checking the status:
This command’s output will show that HTTP traffic is allowed:
OutputStatus: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx HTTP ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx HTTP (v6) ALLOW Anywhere (v6)
With the new firewall rule added, you can test if the server is up and running by accessing your server’s domain name or public IP address in 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:
This will print out a few IP addresses. You can try each of them in your web browser.
As an alternative, you can check which IP address is accessible, as viewed from other locations on the internet:
Type the address that you receive in your web browser and it will take you to Nginx’s default landing page:
http://server_domain_or_IP
If you received a web page that states ”Welcome to nginx” then you have successfully installed Nginx.
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 the following command:
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 you want to modify some insecure defaults. Initiate the script by typing the following:
This script will ask if you want to configure the VALIDATE PASSWORD PLUGIN
.
Warning: Enabling this feature is a judgment call. If enabled, passwords that 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 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.
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, 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
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:
For the rest of the questions, you should press Y
and hit the ENTER
key at each prompt. This will remove some anonymous users and the test database, disable remote root logins, and load these new rules so that MySQL immediately respects the changes we have made.
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 using the auth_socket
plugin to access MySQL fits with your workflow, you can proceed to Step 3. If, however, 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:
Next, check which authentication method each of your MySQL user accounts uses with the following command:
Output+------------------+-------------------------------------------+-----------------------+-----------+
| 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)
This example demonstrates 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:
Then, run FLUSH PRIVILEGES
to tell 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:
Output+------------------+-------------------------------------------+-----------------------+-----------+
| 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)
This example output shows that the root MySQL user now authenticates using a password. Once you confirm this on your own server, you can exit the MySQL shell:
Note: After configuring 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:
After entering the password you set, you will receive the MySQL prompt.
At this point, your database system is now set up and you can move on to installing PHP.
Nginx is now installed to serve your pages and MySQL is 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”. After, you’ll tell Nginx to pass PHP requests to this software for processing.
Note: Depending on your cloud provider, you may need to add Ubuntu’s universe
repository, which includes free and open-source software maintained by the Ubuntu community, before installing the php-fpm
package. You can do this by typing the following command:
Install the php-fpm
module along with an additional helper package, php-mysql
, which will allow PHP to communicate with your database backend. The installation will pull in the necessary PHP core files. Do this by typing the following:
Even with all of the required LEMP stack components installed, you still need to make a few configuration changes in order 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). To do this, create a new server block configuration file using your preferred text editor within the /etc/nginx/sites-available/
directory. In this example, we will be using nano
and the new server block configuration file will say your_domain
, so you can replace it with your own information:
By creating a new server block configuration file, rather than editing the default one, you’ll be able to restore the default configuration if you ever need to.
Add the following content, which was taken and slightly modified from the default server block configuration file, to your new server block configuration file:
server {
listen 80;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name your_domain;
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 directives and location blocks does:
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. If you’re using nano
, you can do this by pressing CTRL + X
then Y
and ENTER
. 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:
Then, unlink the default configuration file from the /sites-enabled/
directory:
Note: If you ever need to restore the default configuration, you can do so by recreating the symbolic link using a command like the following:
Test your new configuration file for syntax errors:
If any errors are reported, go back and recheck your file before continuing.
When you are ready, reload Nginx to make the necessary changes:
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.
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 preferred text editor to create a test PHP file called info.php
in your document root:
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
:
http://your_server_domain_or_IP/info.php
Your browser will load a web page like the following that has been generated by PHP with information about your server:
If your page is as described, 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:
With that, you 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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Awesome guidelines, Now, write an article about installing WordPress with LEMP Stock on Ubuntu 18.04. Thanks!
For those who might be in a similar situation I was able to resolve my issue by starting from scratch. After logging into DO I selected: Create Droplet>Distributions>Ubuntu
My problem was stemming from having selected a Market Place>LEMP 18.04 droplet. When pointing my browser to the IP I was taken to this “Quick Start Guide”, which might need to be fixed by DO to remove any further confusion.
Hello @isaacmtait,
Apologies for my delay in getting back to you. Yes, the message you saw after creating a Droplet with our LEMP One-Click application should have taken you to our product documentation rather than this tutorial. Our engineers are aware of this and are working to update this link soon.
I Always love having my websites run on the latest software and this seems to be the latest setup. Good article I will install WordPress and see how it goes from here.
nice one what else to do now and which editor to use
Thanks… Very usefull!
Why not just
sudo apt-get install mysql-server
? It loads version 5.7.22.By the way: smart of you to point out ``auth_socket``` in 18.04.
Thank you for your comment @dons. I had initially specified the MySQL version number in the install command, which was an oversight on my part. I’ve since updated the command as you suggested to install the latest version of MySQL.
This comment has been deleted
awesome guide thank you
This comment has been deleted
how to install wordpress in ubuntu 18.04??
getting a 502 Bad Gateway with the info.php page
For me, change this line at /etc/nginx/sites-available/default is worked:
old:
new:
Or whatever with your php-fpm version.
How about add line to /etc/hosts
?
502 Bad Gateway
Here’s how to fix it!
Check what kind of Unix Socket you are using! For me, it was written :
Now you need to tell nginx that this is the one socket you’re using!
You need to edit
fastcgi_pass unix
.In Step 4 - the info.php file is downloading instead of displaying it. did i missed something in configurations. please help how to fix this. thanks.
Have the same issue, need help
Hi,
please try to unlink default vhost configuration :
and restart Nginx by doing : systemctl restart nginx.service
You should be able now to display your phpinfo (don’t not forget to remove it after your test ;-) )
Please let me know if it’s OK for you \o/
hello tonton It says “no such file or directory” but the directory is already there.
I personally am following this tutorial after already using the
default
server block configuration file [instead of making a new one like this tutorial suggests]. I also don’t have a domain name and am just using a Google Cloud Public IP. I ran into a 403 error when navigating to my Public IP without specifyingindex.php
, then when I did specifyindex.php
, it downloaded the file instead of displaying it [after ensuring my Google Cloud Firewall config allowed HTTP connections and connections to my specified port].For whatever reason, unlinking then re-linking the
default
file fixed it for me:server { listen MyPort; listen This.Is.My.IP:MyPort; root /var/www/html/app3; index index.php index.html;
}
For people who wants use MariaDB instead MySQL, the steps are the same, but instead of installing the package
mysql-server-5.7
, install the packagemariadb-server
. It worked for me.In Step 4 - the info.php file is downloading instead of displaying it. did i missed something in configurations. please help how to fix this. thanks.
Hello,
This is probably due to the default vhost configuration. Could you try to unlink it :
As a good practice always check Nginx configuration before restarting it :
And let me know if it helped you :)
yes it worked, thanks you
did you modify the code provided by tonton or entered as it is. It is not working for me, saying no such file or directory
I’ve tried all of the fixes suggested here, but info.php keeps on downloading instead of being rendered.
Amazing that there is no response from the author or other DO staff after more than two weeks.
This comment has been deleted
For some reason I got an error saying that php-fpm could not be found. I had to download it from packages.ubuntu.com and install it manually.
I’m testing on a local VM before moving to a droplet. Looks like I had to enable the universe repo.
That’s correct! It can be added using
sudo add-apt-repository universe
Hello, I am having an issue where if I test my php configuration, instead of showing the php.info file it downloads it? What is the issue? I followed through the steps multiple times
Check response here
Are you switching to the
/etc/nginx/sites-enabled
directory before running the commands listed above?When I go to myipaddress/info.php it downloads the file instead of displaying the page. Why?
Hi Everything ok until I try and load info.php into browser, it downloads it instead. Notice you don’t seem to be able to solve the problem from the comments below. Is it fixable?
If you have problems installing php-fpm on a fresh Ubuntu 18.04 is because by default the universe repo is disable.
You can fix it running:
sudo add-apt-repository universe
Source: https://askubuntu.com/questions/1069649/how-to-install-php-fpm-on-clean-install-of-ubuntu-18-04-server
Pity about the fact that php-fpm is NOT FOUND… I hate linux, Changes at the whim of an unknown person…
Amazing guide fellas! Worked like a charm :)
There is one missing step for people who uses Ubuntu Server 18.04:
The apt-get install php-fpm php-mysql will not be found until you add-apt-repository universe
Thanks for your great documentations!
How to install MYSQL 8.0 in Ubuntu 18.10??? any one.
When I type http://my_server_domain/ in my browser, it displays the default nginx page. But when I type http://my_server_domain/info.php it does not show the page with phpinfo, rather it downloads the file info.php. What mistake did I make?
For step 3, editing the server block file, I had already completed the steps in the tutorial for using LetsEncrypt with Ubuntu 18.04, so the file mydomainname.com already has a bunch of stuff in it (starting with listen to port 443 etc).
Should I create a separate server block file for the PHP setup, or do I need to edit that same mydomainname.com file?
If the latter, which bits from the example above should I add and where?
Please ignore this message
I completed the Let’s Encrypt with Nginx and Ubuntu server 18.04 before I followed these steps. I have my own domain name pointing at the server. I left the default file alone and added the relevant lines to my domain name file for PHP.
When I type myname.com/info.php I get a 404 message. Could this be due to the fact I ran the SSL tutorial before this one?
I get a ‘bad gateway 502’ message when I type domainname.com/info.php. Regular html files in the same folder do show in the browser (when I type domainname.com/test.html. Php is active on my server, and there are no bad scripts in nginx. I have deleted the “default” file in websites-enabled, but left the one in websites-availabe.
Problem solved. It was a stupid typo (fm.sock instead of fpm.sock).
Hi I seen this below as well, it is downloading the file instead executing any idea?
Hello @r2d23k,
Apologies for the late reply. I just ran through this tutorial as written and everything worked as expected. I was, however, able to replicate the issue of the
info.php
file being downloaded instead of rendered by skipping some of the steps outlined in Step 3.If you’re still experiencing this issue, I’d first recommend that you double check the
server_name
directive in your server block file. This directive should point to your server’s public IP address or a domain name that has been associated with the server:Then double check that you’ve linked your server block file to the
/sites-enabled/
directory with the following command:If you did perform each of those steps and the problem persists, it may be that the
php-fpm
package wasn’t installed correctly. Can you confirm that it was successfully installed through APT?HI all just wanted to give a quick thumbs up feedback for this tutorial and a lot of other tutorials this community has.
I have an idea but unfortunately not enough bash script knowledge to implement it. at the same time i think that it may be mega helpful for the community
I’m a developer that uses this tutorial combined with initial server setup tutorial basically every time i setup an environment. (and I do that a lot) I noticed there is a tutorial for automating initial server setup
and I think it would be a great idea, to do 2 things 1-simple- create a lemp setup automation script 2-advanced- and a more interesting approach create a script generator app(service) that enables us to create an a setup automation script from combining a a few existing automations scripts. basickly building a script as lego from a few existing scripts
PS: it may already exist, and i may not know about it, sorry for this post if this is the case if not it’s a great idea for a dedicated website/service
It works. Thank you
“This script will ask you to supply a password for use within the MySQL system.”
The script will NOT do this first, it will do it AFTER.
*"1vcpu-1gb-nyc3-01:~$ sudo mysql_secure_installation
Securing the MySQL server deployment.
Connecting to MySQL using a blank password.
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?"*
You need to say no first, THEN you are asked for a password for root. A small detail, but one that is sure to trip up novices or people simply following instructions.
The other, routinely reported issue, is that following all related startup guides (including this one), results in the info.php file being downloaded, not displayed. Again, not a huge issue, but it scares new users into thinking they’ve messed up somewhere, and should be fixed. On that note, I’m a bit surprised it has been this way for so long, without a fix - I’ll see about pushing someone to get this updated.
All in all, great guide(s) - between my knowledge of doing this a few years ago, and the advances in both tech and DigitalOcean, I found setting up a VPS much easier this time around.
Hello @Porter!
Thank you so much for bringing this to our attention - I hadn’t been receiving notifications of new comments on this guide so I was unaware that people were running into issues with it.
I just went through this tutorial as it was written and everything worked as expected. I was, however, able to replicate the issue of the
info.php
file being downloaded instead of rendered by skipping some of the steps outlined in Step 3. These include:example.com
server block file to thesites-enabled
directoryserver_name
directive in theexample.com
server block file to point to the correct domain or IP address.I’d recommend that anyone whose
info.php
file is being downloaded instead of rendered in the browser double check that they’ve completed these two tasks.I also saw it mentioned in a few comments that unlinking the
default
server block file can help to prevent theinfo.php
file from being downloaded. The page rendered correctly for me without unlinking it, but I’ve added theunlink
command to Step 3 since having both server blocks enabled is unnecessary.Regarding your comment about the
mysql_secure_installation
script, I can absolutely see how what I’d written was confusing. I’ve adjusted some of the language in that section to hopefully better reflect what readers will experience.Thanks again for reaching out and bringing these matters to our attention.
after using ALTER USER command. it sends me an error every time i try to login to mysql
ERROR 1045 (28000): Access denied for user ‘root’@‘localhost’ (using password: NO)
t.t it’s so bad if i skip it?
Hello @luisenrique,
Thanks for your question, and apologies for the confusion. After configuring your root MySQL user to authenticate with a password instead of the
auth_socket
plugin, you will no longer be able to access the MySQL prompt with thesudo mysql
command. Instead, you’ll need to run the following:This command includes the
-u
option, which allows you to specify which user you’d like to access MySQL as (in this case, root), and the-p
option, which informs MySQL that you want to authenticate with a password. I’ve added this command in a note near the end of Step 2, which I hope helps to clear up this point.Of course, authenticating with a password is completely optional. If you’d prefer to authenticate with the
auth_socket
plugin (meaning, without a password), then you do not need to run theALTER USER
command.I am stuck on Step 1.
I have followed the directions but when I “test if the server is up and running by accessing [my} server’s domain name or public IP address in [my] web browser.” I get the message:
Please log into your Droplet with SSH to configure the LEMP installation. See the LEMP One-Click Quickstart guide for detailed assistance.
What am I doing wrong?
This comment has been deleted
This comment has been deleted
Thanks for this awesome guide.
However, I do have a question: When we are configuring PHP processor on a “server block level”, the configuration file was written in the system default root directory:
root /var/www/html;
insudo nano /etc/nginx/sites-available/example.com
Shouldn’t it be written in
/var/www
directory instead of the system default root directoryroot /var/www/html;
, like the following:root /var/www/example.com/html;
as guided by the previous How To Install Nginx on Ubuntu 18.04 in Step 5 – Setting Up Server Blocks (Recommended)?I am really confused about this set up. It’s really appreciated if someone can explain it to me. Cheers guys!!
Hi @gchenpz!
Thanks for your question. The process described in How To Install Nginx on Ubuntu 18.04 is more to explain the concept of server blocks, rather than outline a particular ‘correct’ way to set up Nginx. In Nginx, the web root can be any directory on the system as long as the correct ownership and permissions are in place.
This tutorial, on the other hand, was originally written with the goal of getting a LEMP stack up and running as quickly as possible. For that reason, it uses the default web root directory (
/var/www/html
) to avoid the steps of creating a new web root directory, changing ownership of the directory, and applying the appropriate permissions.I hope this helps to resolve your confusion.
@mdrake yo bro you totally posted your root password hash. i tried contacting you on linkedin and got bored of waiting
Can anyone help me to migrate from Apache to Nginx server? I Cannot see any process here. I want to remove the Apache and install the Nginx without affecting the current data.
This guide missing some information. I did everything correctly and nginx server running but still seeing digitalocean installation guide when i hit server root by ip. Can’t see “welcome to nginx” page.
After installing LEMP stack with a new droplet and opening domain directs me to read this doc. Dude i already installed LEMP stack. Why i am still how to install LEMP page?
Mark, you are wizard! This first manual that i can start. Usually web servers what i attempted to work got broken them neck.
Thank you very much. This was very useful. But now I have an issue with my domain name and even my server IP. I can’t access my server through my domain name. I need some help. I don’t know what’s the actual cause of this problem.
It may be because I delete DNS records containing digitalocean DNS. But if this is the problem then why my IP is not working.
Note: My root location is different than what’s mention above. It’s
/home/user/public
. Also, my nginx server is running with 0 errors.Please update the guide to use MySQL 8 instead of 5.
Thank you very much
I got stuck at the info.php test instruction. Looks like Nginx doesn’t interpret PHP therefore aks me to download the file. I followed exactly your instructions… How come?
nginx php 502 bad gateway fpm
I solved with this 2 steps:
1 - Primeiro identifiquei qual era o FPM
2 - Depois habilitei o FPM
And then you test:
At last:
Very good
For those seeing the info.php download instead of execute, I failed the same issue.
1 or both of the following helped me
sudo systemctl reload php7.4-fpm
sudo chmod a+x /var/www/html/info.php