---
title: Setting Up a LEMP Stack (Linux, Nginx, MySQL, PHP) on Ubuntu 22.04
description: "The LEMP stack (Linux, Nginx, MySQL, PHP) is a collection of software used to serve dynamic web pages and PHP applications. It consists of a Linux operating system, the Nginx (pronounced \"Engine-X\") web server, a MySQL database for data storage,…"
url: "https://truehost.com/support/knowledge-base/setting-up-a-lemp-stack-linux-nginx-mysql-php-on-ubuntu/"
updated: "2024-11-01"
category: Cloud servers in Kenya
---

# Setting Up a LEMP Stack (Linux, Nginx, MySQL, PHP) on Ubuntu 22.04

The LEMP stack (Linux, Nginx, MySQL, PHP) is a collection of software used to serve dynamic web pages and PHP applications.

It consists of a Linux operating system, the Nginx (pronounced "Engine-X") web server, a MySQL database for data storage, and PHP for handling dynamic content.

This guide will walk you through setting up a LEMP stack on a server running Ubuntu 22.04. With Ubuntu managing the Linux component, we’ll cover how to configure each of the remaining parts of the stack.

## Prerequisites

- Ubuntu 22.04
- A user account with admin or sudo access

## Step 1: Installing the Nginx Web Server

Nginx is a popular, efficient web server that we'll use to serve pages to our visitors. Begin by updating your server’s package index:

```
sudo apt update
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image.png)

Then install Nginx:

```
sudo apt install nginx
```

Press **Y** and **Enter** to confirm the installation.

![](https://truehost.com/support/wp-content/uploads/2024/11/image-1.png)

#### **Allowing Nginx Through the Firewall**

If you’re using UFW (Uncomplicated Firewall), you’ll need to allow HTTP traffic through it. Check available UFW application profiles with:

```
sudo ufw app list
```

Enable only HTTP traffic on port 80, as we’re not configuring SSL here:

```
sudo ufw allow 'Nginx HTTP'
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-2-1024x168.png)

Verify the firewall status to confirm:

```
sudo ufw status
```

To verify that Nginx is running, open your server’s public IP or domain in a web browser. If unsure about your public IP, run one of the following commands to see it.

```
$ ip addr show
$ hostname -I
```

In your browser, navigate to:

```
http://server_domain_or_ip_address
```

This should display the Nginx default landing page.

![](https://truehost.com/support/wp-content/uploads/2024/11/image-3-1024x249.png)

## Step 2: Installing MySQL

With Nginx installed, we’ll move on to installing MySQL, which will manage and store site data.

You can also use MariaDB. Please refer to **[these steps](https://truehost.com/support/knowledge-base/how-to-install-mariadb-on-ubuntu-22-04/)** on how to install MariaDB database on Ubuntu

For MySQL, run:

```
sudo apt install mysql-server
```

After installing MySQL, it is a good idea to run a security script included with it

```
sudo mysql_secure_installation
```

You’ll be prompted to configure the VALIDATE PASSWORD PLUGIN—type Y for yes or any other key to continue without enabling it.

If you select “yes,” you’ll be prompted to choose a level of password validation. I prefer that you choose level 1.

It is fine to select yes fort he rest of the prompts, but then you can also choose differently according to your preference.

![](https://truehost.com/support/wp-content/uploads/2024/11/image-5.png)

Once done, check if you can log in to the MySQL console:

```
sudo mysql
```

This command connects to the MySQL server using the administrative database user root, indicated by sudo. The expected output is as follows:

![](https://truehost.com/support/wp-content/uploads/2024/11/image-4.png)

You may then run the command below to exit the console;

```
exit
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-6.png)

## Step 3: Installing PHP

Next, install PHP to generate dynamic content. Nginx uses **PHP-FPM** (FastCGI Process Manager) for this purpose. Install PHP and the PHP MySQL extension with:

```
sudo apt install php8.1-fpm php-mysql
```

Press **Y** and **Enter** to confirm.

## Step 4: Configuring Nginx to Use PHP Processor

We’ll configure Nginx to handle PHP requests. By default, Nginx uses the directory `/var/www/html` for its root web directory. We’ll create a new directory for our website and set up a configuration file.

In the steps below, remember to replace *your_domain* with your actual domain or subdomain. I will use *doll.tke.co.ke*

1. Create the web root directory:

```
sudo mkdir /var/www/your_domain
```

2. Assign ownership of the directory to the current user:

```
sudo chown -R $USER:$USER /var/www/your_domain
```

3. Open a new configuration file in the **sites-available** directory:

```
sudo vi /etc/nginx/sites-available/your_domain
```

4. Add the following configuration:

```
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;
    }
}
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-7.png)

Below is what each of the directives do

- **listen** specifies the port.
- **root** sets the document root directory.
- **index** prioritizes `index.html` over `index.php`.
- **server_name** specifies the domain names.
- **location /** verifies file existence, returning a 404 if not found.
- **location ~ .php$** handles PHP files via FastCGI.
- **location ~ /.ht** denies access to `.htaccess` files.

5. Save and close the file (in **vi**, press **Esc**, type `:wq`, and press **Enter**).

6. Enable your configuration:

```
sudo ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
```

7. Unlink the default configuration:

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

8. Test your configuration for syntax errors:

```
sudo nginx -t
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-8.png)

9. Reload Nginx to apply the changes:

```
sudo systemctl reload nginx
```

10. Add a sample **index.html** file to verify that your new server block works:

1.

```
vi /var/www/your_domain/index.html
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-9-1024x797.png)

11. Visit `http://your_domain` in your browser to confirm.

![](https://truehost.com/support/wp-content/uploads/2024/11/image-10-1024x702.png)

## Step 5: Testing PHP with Nginx

To test PHP, create a file called **info.php** in your document root:

```
vi /var/www/your_domain/info.php
```

Add the following code:

```
<?php
phpinfo();
?>
```

Access this page by navigating to:

```
http://your_domain/info.php
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-11-1024x590.png)

After confirming, delete the file to avoid exposing sensitive information:

```
sudo rm /var/www/your_domain/info.php
```

## Step 6: Testing Database Connection from PHP

Create a test database and user in MySQL:

**Log in to MySQL:**

```
sudo mysql
```

**Create a new database:**

- Replace test_db with your preferred database name

```
CREATE DATABASE test_db;
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-14.png)

**Add a new user:**

- Replace test_user with your preferred user name

```
CREATE USER 'test_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-13.png)

**Note:**When running the command you may get this error ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
In that case, just ensure that your password has a mixture of special characters, numbers, uppercase and lowercase characters, then re-run it.

**Grant the user privileges on the new database:**

```
GRANT ALL ON test_db.* TO 'test_user'@'%';
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-12.png)

**Exit MySQL:**

```
exit
```

To confirm that the new user has the correct permissions, log into the MySQL console again using the custom user credentials.

Be sure to include the `-p` flag in the command, as it will prompt for the password set when creating the "test_user" user.

```
mysql -u test_user -p
```

Enter your password and confirm to access test_DB.

You can then check the databases available;

```
SHOW DATABASES;
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-15-1024x433.png)

Let’s now create a test table named “**tech_list**.” Execute the following statement from the MySQL console:

```
CREATE TABLE test_db.tech_list (tech_id INT AUTO_INCREMENT,technology VARCHAR(255),PRIMARY KEY(tech_id));
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-16-1024x187.png)

You may now insert values into the table by running multiple inatances of the command below

```
INSERT INTO test_db.tech_list (technology) VALUES ("IOT");
INSERT INTO test_db.tech_list (technology) VALUES ("Cloud");
INSERT INTO test_db.tech_list (technology) VALUES ("DevOPs");
INSERT INTO test_db.tech_list (technology) VALUES ("ML");
INSERT INTO test_db.tech_list (technology) VALUES ("Networking");
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-17-1024x258.png)

You could check the entries using the command below;

```
SELECT * FROM test_db.tech_list;
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-18.png)

You may exit the MySQL console using the **exit** command.

## Test MySQL Connection

To test, create a PHP script to connect to MySQL:

Open a file called **testlist.php**:

```
vi /var/www/your_domain/testlist.php
```

Add PHP code to connect and query. In the code below, remember to replace the dummy database details with your own.

```
<?php
$conn = new mysqli("localhost", "test_user", "password", "test_db");

if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

$sql = "SELECT * FROM tech_list";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        echo $row["tech_id"] . ": Technology: " . $row["technology"] . "<br>";
    }
} else {
    echo "0 results";
}

$conn->close();
?>
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-21.png)

Access this script:

```
http://your_domain/testlist.php
```

![](https://truehost.com/support/wp-content/uploads/2024/11/image-22.png)

## Author's final word

Congratulations! You’ve successfully set up a LEMP stack on Ubuntu 20.04, creating a powerful foundation to host PHP-based applications. This configuration, combining Nginx and MySQL, is optimized for speed and security in dynamic web hosting environments.
