Master LEMP Stack Installation: Set Up Linux, Nginx, MySQL, PHP on Ubuntu

Master LEMP Stack Installation: Set Up Linux, Nginx, MySQL, PHP on Ubuntu

Introduction

Setting up a LEMP stack—Linux, Nginx, MySQL, and PHP—is a powerful way to host dynamic websites and applications on an Ubuntu server. This guide walks you through installing and configuring each component, ensuring your server is optimized for performance and scalability. With Nginx handling web requests, MySQL managing your data, and PHP processing dynamic content, you’ll have the perfect setup for building robust, high-performance sites. We’ll cover step-by-step instructions for installing each tool and connecting them seamlessly, so you can easily get your LEMP stack running on Ubuntu. Let’s dive into creating a stable, efficient server environment for your web projects.

What is LEMP stack?

The LEMP stack is a set of software tools used to run dynamic websites and applications. It includes a Linux operating system, an Nginx web server, a MySQL database for storing data, and PHP for processing the site’s content. This combination provides a powerful and efficient way to host websites, especially those built with PHP, on an Ubuntu server.

Step 1

Alright, let’s get started! If you want your site to actually show web pages to visitors, you need a good web server. This is where Nginx comes in – it’s a fast, lightweight server designed to handle a lot of traffic while keeping things running smoothly. It’s like the reliable engine of the internet, able to manage hundreds, or even thousands, of connections at the same time.To begin, you’ll use APT, the package manager that makes installing software on your Ubuntu server simple. But before jumping into the installation, it’s always a good idea to update your server’s package list first. This makes sure you’re installing the latest versions of everything. To do this, just run:

sudo apt update
Once the update is done, you can install Nginx. Just run this:
sudo apt install nginx
When it asks for confirmation, press Y and hit ENTER. In just a few moments, Nginx will start installing, and it will automatically start up once done. You’re now ready to serve web pages!But wait—if you have UFW (Uncomplicated Firewall) enabled on your server, which is likely since it’s part of the initial setup, you’ll need to change the firewall settings to let Nginx accept incoming connections. Nginx registers a few application profiles with UFW once it’s installed, and these profiles decide which types of traffic are allowed to reach your server. To see the available profiles, run:
sudo ufw app list
You should see something like this:
Output
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
Since you haven’t set up SSL yet, you only need to allow regular HTTP traffic on port 80 (the usual for web traffic). To do this, run:
sudo ufw allow ‘Nginx HTTP’
After that, you’ll want to make sure the rule was added correctly. You can check this by running:
sudo ufw status
You should see something like this:
Output
Status: active
To                         Action      From
—                         ——      —-
OpenSSH                    ALLOW       Anywhere
Nginx HTTP                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx HTTP (v6)            ALLOW       Anywhere (v6)
This confirms that HTTP traffic is now allowed through, and you’re all set!Now for the real test: is Nginx working? Let’s find out. Open a web browser and type your server’s domain name or public IP address in the address bar. If you don’t have a domain set up or aren’t sure what your public IP address is, don’t worry! You can easily find it by running one of these commands:
ip addr show
or
hostname -I
This will give you the IP addresses linked to your server. If there’s more than one, just try entering each one in your browser’s address bar.Alternatively, you can check from another location on the internet by running:
curl -4 icanhazip.com
Once you have the IP address, type it into your browser like this:
http://server_domain_or_IP If everything’s set up right, you should see Nginx’s default landing page, which confirms the web server is up and running smoothly. If you see that page, congratulations! You’ve successfully installed Nginx and set it up to accept HTTP traffic. Your server is now ready to serve web pages. Install Nginx on Ubuntu

Step 2

Now that your Nginx web server is all set up, it’s time to add the next key component: a database system. That’s where MySQL comes in. If you’ve worked with web apps before, you probably know that databases are the core of most dynamic websites. MySQL is a great, reliable option, especially when used with PHP, as they work together smoothly to power dynamic sites. Here’s how to get started with MySQL: First, like you did with Nginx, use the APT package manager to install MySQL on your server. No need for anything complicated—just run this simple command:

sudo apt install mysql-server
You’ll be asked to confirm, so press Y and hit ENTER. The installation will begin, and before you know it, your MySQL server will be up and running. But hold on—before you start setting up databases, it’s a good idea to run a security script that comes pre-installed with MySQL. This script helps secure things by removing insecure default settings and locking down access to your database. To launch the security script, just run:
sudo mysql_secure_installation
Once you do that, you’ll be asked a few questions. The first one is about the VALIDATE PASSWORD PLUGIN, which checks how strong your database passwords are. Turning this on is optional. If you want a little extra security, feel free to enable it, but it’s not necessary. If you decide to use it, passwords that don’t meet the strength requirements will be rejected. You’ll be given three password strength options to choose from:
0 = LOW : Passwords need to be at least 8 characters.
1 = MEDIUM : Passwords need to be at least 8 characters and include a mix of numbers, uppercase and lowercase letters, and special characters.
2 = STRONG : Passwords need to meet the same requirements as medium, but also undergo a dictionary check.For most people, the medium level (option 1) is a good balance between security and ease of use. After selecting the level, you’ll be prompted to set and confirm a password for the MySQL root user. Keep in mind that the MySQL root user isn’t the same as the system root user. The MySQL root user has full control over the MySQL server, so make sure you pick a strong password. Once you enter your password, you’ll see how strong it is. If you’re happy with it, press Y to move forward.Next, the script will clean things up by removing anonymous users, disabling remote root logins, and deleting the test database. For each prompt, press Y to confirm and improve the security of your MySQL setup. Once that’s done, it’s time to check that everything’s working as it should. Try logging into the MySQL console as the root user:
sudo mysql
If everything’s set up right, you’ll see this message:
Output
Welcome to the MySQL monitor.Commands end with ; or \g.Your MySQL connection id is 10Server version: 8.0.28-0ubuntu4 (Ubuntu)mysql>
If you see this, congratulations—you’ve successfully logged into MySQL! To exit the MySQL console, simply type:
exit
Now, you might be wondering why, even though you set a password for the MySQL root user, you didn’t need to enter it when logging into the MySQL console. That’s because, by default, Ubuntu uses the auth_socket plugin for MySQL authentication. This method allows system users with sudo privileges to log into MySQL without a password. It’s a secure way to ensure that only authorized users can access MySQL. However, if you plan to use the root user in PHP applications, this method won’t work. The root user, as it’s currently set up, won’t work for PHP because it relies on the auth_socket plugin. To make things more secure and flexible, it’s a good idea to create specific MySQL users with limited privileges for each database on your server.Also, just so you know—older versions of the MySQL PHP library (mysqlnd) don’t support the default authentication method (caching_sha2_authentication) introduced in MySQL 8. If that applies to you, you might need to configure your MySQL users to use the mysql_native_password authentication method instead.With MySQL installed, secured, and ready to go, it’s time to move on to the next step: installing PHP. This will complete your LEMP stack and bring you one step closer to running a fully dynamic web server.Install MySQL on Ubuntu

Step 3

Alright, now that Nginx is serving your website’s content and MySQL is managing your data, the next step is installing PHP. This is where things start to get interesting—PHP is what powers all those interactive, dynamic websites. It lets web pages interact with databases, process forms, and handle server-side tasks that keep the internet running.If you’ve worked with servers like Apache before, you might be used to PHP requests being handled automatically. But with Nginx, it’s a bit different. Nginx doesn’t have a built-in PHP processor, so it needs a little help. That’s where PHP-FPM (FastCGI Process Manager) comes in. With this setup, Nginx sends PHP requests to PHP-FPM, which processes them and sends the results back to Nginx to serve to your visitors. The benefit of this approach? It gives you better performance and scalability, especially for PHP sites that handle a lot of traffic.But here’s the thing: it does need a bit of extra configuration. The first step is to install php8.1-fpm, which is the PHP FastCGI Process Manager that lets Nginx communicate with the PHP interpreter. Depending on your operating system, the version might change over time, but for now, php8.1-fpm is the most stable version. Along with php8.1-fpm, you’ll also need the php-mysql package. This is a PHP module that lets PHP talk to the MySQL database you set up earlier. You can think of php-mysql as the bridge between PHP and MySQL, making sure they work together smoothly.Don’t stress too much about the technical side of things. Installing php8.1-fpm will automatically pull in all the other PHP components as dependencies. So, you only need to install the two packages—php8.1-fpm and php-mysql.To install them, just run:

sudo apt install php8.1-fpm php-mysql
When prompted, press Y and hit ENTER to confirm, and the installation will start. After a few moments, PHP and the MySQL module will be installed, and you’ll have a fully functional PHP setup, perfectly integrated with Nginx and MySQL.Next up is configuration. We need to tell Nginx how to handle PHP requests. This step is crucial because without it, your web server won’t know how to process PHP files, and your site won’t work as expected. This configuration step ensures that everything—Nginx, PHP, and MySQL—works together smoothly to process and deliver dynamic content to your visitors.Install PHP on Ubuntu

Step 4

Alright, now that Nginx is handling your content and MySQL is managing all that precious data, the next big step in our journey is getting things set up for multiple domains or websites on your server. You might wonder, “How do I manage several websites on a single server?” Well, Nginx has a great feature called server blocks (think of them like Apache’s virtual hosts, but with a bit more style). These blocks let you organize and manage multiple sites without any hassle.Let’s say your website’s name is your_domain—but don’t get too attached to it, because you’ll want to swap that out with your actual domain name when you do this for real. In Ubuntu, Nginx starts off with one default server block, which points to /var/www/html. This works fine for a single website, but once you add a second website, that directory gets a bit crowded, right? No worries, though—we’ll keep /var/www/html as it is and create a fresh new folder just for your_domain. This keeps everything clean and tidy!Here’s how to do it:First, let’s create the root web directory for your site. Just run:

sudo mkdir /var/www/your_domain
Once that’s done, we need to make sure you have the right permissions to manage your new directory. So, let’s assign ownership of that folder to your current system user (that’s you!):
sudo chown -R $USER:$USER /var/www/your_domain
Next, we need to let Nginx know about your_domain by creating a new configuration file in the sites-available directory. Open your favorite text editor (we’ll use nano for this example):
sudo nano /etc/nginx/sites-available/your_domain
This is where the magic happens. You’ll be setting up a few important things here: listening on port 80, telling Nginx which domain to respond to, and pointing it to the right folder for your website’s files. Here’s the basic configuration to get started:

server {
    listen 80;
    server_name your_domain www.your_domain;
    root /var/www/your_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/php8.1-fpm.sock;
    }    location ~ /\.ht {
        deny all;
    }
}
Let’s break it down a bit:

  • listen : We’re telling Nginx to listen on port 80, which is the standard for HTTP traffic.
  • server_name : Here, you’ll put your actual domain or public IP address instead of your_domain. This tells Nginx which domain or IP to respond to.
  • root : This tells Nginx where to find the website files. We’ve set it to /var/www/your_domain so it knows where to look.
  • index : This tells Nginx the order of priority for index files. It looks for index.html first, then index.htm, and finally index.php.
  • location / : If someone requests a file or folder that exists, this block will serve it. If not, it returns a 404 error.
  • location ~ .php$ : Here’s where we tell Nginx to pass any PHP requests to PHP-FPM (FastCGI Process Manager), so it can process those requests.
  • location ~ /.ht : This block is a security measure—Nginx won’t process or serve any .htaccess files, which could otherwise expose sensitive info.

Once you’ve inserted the configuration, save and exit nano. To do that, press CTRL+X, then press Y to confirm the changes, and hit ENTER.Now, let’s activate the configuration. We’ll create a symbolic link from sites-available to sites-enabled, where Nginx looks for active configurations:

sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
Now, let’s remove the default configuration since we’ve created our own:
sudo unlink /etc/nginx/sites-enabled/default
No worries, if you ever want to bring back the default config, you can just run:
sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/
Before you finish up, it’s a good idea to test your configuration for any errors. Run:
sudo nginx -t
If there are any mistakes, go back to the configuration file and check for typos or misconfigurations. Once it’s all clear, reload Nginx to apply the changes:
sudo systemctl reload nginx
Now your site is technically live, but there’s one small catch: /var/www/your_domain is still empty! You need something to test the server block. Create a simple index.html file to do that:
nano /var/www/your_domain/index.html
Pop this in there:

<html>
  <head>
    <title>your_domain website</title>
  </head>
  <body></p>
<h1>Hello World!</h1>
<p>This is the landing page of <strong>your_domain</strong>.</p>
<p>  </body>
</html>
Now, open your web browser and type in the server’s domain name or IP address (the one you set in the server_name directive):
http://server_domain_or_IP If everything went smoothly, you should see your “Hello World!” page. This means your Nginx server block is working as expected. You can leave this as a placeholder for now until you set up a PHP-based index page later on.Just remember, once you switch to PHP content, Nginx will prioritize index.html over index.php, so you’ll need to remove or rename index.html once you’re ready for dynamic content.And there you go! You’ve successfully set up your Nginx server to handle multiple domains, and in the next step, we’ll dive into configuring PHP to make your site truly dynamic.Installing Nginx on Ubuntu

Step 5

Alright, we’re almost there! Your LEMP stack should now be set up and running. But before you get too excited and think everything’s perfect, let’s do a quick check to make sure Nginx is handling PHP files properly. Trust me, this step is important to ensure your server is working just like you want it to.Now, here’s what we’ll do: we’re going to create a simple test PHP file. This file will give you all the info about your server’s PHP setup. Think of it like a quick diagnostic tool to confirm everything is running smoothly.Start by creating a new file called

nano /var/www/your_domain/info.php
in your document root. Once the file is open, we’ll add a bit of magic inside. Just drop in this simple piece of PHP code:

<?php
phpinfo();
What this code does is pretty neat: it generates a full webpage showing important details about your PHP environment—like the PHP version, installed modules, and other settings your server is running. It’s like popping open the hood of your server and checking out everything under the engine.Once you’ve added the code, save the file and exit nano. To do that, press CTRL+X , then hit Y to confirm your changes, and finally press ENTER . Now, you’ve got a handy little PHP script that shows you everything you need to know about your PHP setup.Now, the fun part—testing! Open your web browser and type in your server’s domain name or public IP address, but don’t forget to add /info.php at the end of the URL to point to the file you just created. So, in your browser’s address bar, type something like this: http://server_domain_or_IP/info.php If everything is working as expected, Nginx will display a page with all the details about your PHP environment. You’ll see the PHP version, installed modules, and other config bits. If that happens, congrats—you’ve just confirmed that PHP is fully integrated with Nginx, and everything’s running smoothly.But don’t get too comfortable—this file is a bit of a security risk. It shows important details about your server that could be exploited if someone with bad intentions gets access to it. So, once you’ve confirmed that everything is working fine, you should delete the info.php file from your server.To delete the file, just run:
sudo rm /var/www/your_domain/info.php
Don’t worry—if you ever need it again for debugging or checking your PHP setup in the future, you can always regenerate it. But for now, it’s best to keep your server clean and secure.That’s it! Your PHP setup is good to go, and you’ve taken the right steps to make sure everything is working properly.Installing MySQL on Ubuntu

Step 6

Alright, you’ve made it this far, and your LEMP stack is up and running! Now, let’s make sure everything is working smoothly, especially the connection between PHP and MySQL. To do that, we’ll set up a test database, add some dummy data, and query it using PHP. This step will confirm that PHP and MySQL are working well together on your server.But before we dive into testing, you’ll need to set up a database. Here’s the deal—you’ll need to create a MySQL user with the right privileges. Don’t worry, it’s super easy once you get the hang of it!Start by logging into the MySQL console as the root user. Open your terminal and type:

sudo mysql
Now that you’re in, let’s create a fresh new database. Type this command into the console:
CREATE DATABASE example_database;
Here’s where it gets fun—you’re going to create a new MySQL user. This user will have full privileges to access the shiny new example_database. Just remember, in the code below, you’ll want to replace ‘password’ with something more secure:
CREATE USER ‘example_user’@’%’ IDENTIFIED WITH mysql_native_password BY ‘password’;
Okay, now that our example_user is set up, it’s time to give them permission to work with example_database. This means the user will have full control over the database but won’t mess with anything else. You can do that with this:
GRANT ALL ON example_database.* TO ‘example_user’@’%’;
Once you’ve done that, it’s time to exit the MySQL console:
exit
Next, let’s test if our example_user can actually access the database. Let’s log in as this user and check if we can see our example_database. Use this command, and don’t forget to type the password you set up:
mysql -u example_user -p
Once you’re in, type this to see if you can access the database:
SHOW DATABASES;
You should see something like this:
Output

+——————–+
| Database           |
+——————–+
| example_database   |
| information_schema |
+——————–+
Great, the example_database is there! Now let’s move on to creating a table to hold some dummy data. Let’s make a table called todo_list, where we can add some test tasks. Run this:
CREATE TABLE example_database.todo_list (
  item_id INT AUTO_INCREMENT,
  content VARCHAR(255),
  PRIMARY KEY(item_id)
);
Alright, now you need to populate the table with some sample data. Let’s add a few tasks. You can run this command as many times as you want to add different items to your list:
INSERT INTO example_database.todo_list (content) VALUES (“My first important item”);
Let’s check if everything worked by running:
SELECT * FROM example_database.todo_list;
You should see something like this:
Output

+———+————————–+
| item_id | content                  |
+———+————————–+
|       1 | My first important item  |
|       2 | My second important item |
|       3 | My third important item  |
|       4 | And this one more thing  |
+———+————————–+
Now that you’ve verified the data is in there, it’s time to exit the MySQL console again:
exit
At this point, we’re ready to connect to the database using PHP. You’re going to create a simple PHP script that queries the todo_list table and displays the tasks on your web page. Create a new file called todo_list.php in your web directory by typing:
nano /var/www/your_domain/todo_list.php
Then, add this PHP code to the file:

<?php
$user = "example_user";
$password = "password";
$database = "example_database";
$table = "todo_list";try {
  $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
  echo "

<h2 id="todo">TODO</h2>
<ol>“;
  foreach($db->query(“SELECT content FROM $table”) as $row) {
    echo “</p>
<li>” . $row[‘content’] . “</li>
<p>“;
  }
  echo “</ol>
<p>“;
} catch (PDOException $e) {
  print “Error!: ” . $e->getMessage() . ““;
  die();
}
This script connects to MySQL, grabs the content from the todo_list table, and displays it in an ordered list on your web page. If something goes wrong, it’ll show an error message.Once you’ve added that code, save and exit the file. Now, open your browser and type in the domain name or IP address you configured earlier, followed by /todo_list.php . So, if your IP address is 192.168.1.100, you’d type this into the browser: http://192.168.1.100/todo_list.php When you hit Enter, you should see a list of tasks you just added, looking something like this:
Output

My first important item
My second important item
My third important item
And this one more thing
Boom! That confirms that your PHP setup is properly connected to MySQL and is able to interact with your database. And just like that, your server is ready to serve dynamic content using PHP, Nginx, and MySQL. You’ve successfully completed the setup of your LEMP stack. Congratulations!Install MySQL on Ubuntu

Conclusion

In conclusion, setting up a LEMP stack with Linux, Nginx, MySQL, and PHP on Ubuntu provides a powerful and efficient foundation for hosting dynamic websites and applications. By following this guide, you’ve learned how to install and configure each component, ensuring seamless integration for optimal performance. From setting up Nginx to processing PHP requests and managing MySQL databases, each step is crucial for creating a stable server environment.As the demand for dynamic, high-performance web applications grows, mastering LEMP stack installation will be a valuable skill for developers. In the future, staying updated with new PHP and Nginx features, as well as security patches, will be key to maintaining a secure and efficient server setup. With this solid foundation, you’re ready to take your web hosting capabilities to the next level.Now that you’ve successfully completed the LEMP stack setup on Ubuntu, you’re well on your way to building robust, scalable websites and applications.

Install Linux Nginx MySQL PHP LEMP Stack on Ubuntu Guide

Alireza Pourmahdavi

I’m Alireza Pourmahdavi, a founder, CEO, and builder with a background that combines deep technical expertise with practical business leadership. I’ve launched and scaled companies like Caasify and AutoVM, focusing on cloud services, automation, and hosting infrastructure. I hold VMware certifications, including VCAP-DCV and VMware NSX. My work involves constructing multi-tenant cloud platforms on VMware, optimizing network virtualization through NSX, and integrating these systems into platforms using custom APIs and automation tools. I’m also skilled in Linux system administration, infrastructure security, and performance tuning. On the business side, I lead financial planning, strategy, budgeting, and team leadership while also driving marketing efforts, from positioning and go-to-market planning to customer acquisition and B2B growth.

Any Cloud Solution, Anywhere!

From small business to enterprise, we’ve got you covered!

Caasify
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.