Cantech Knowledge Base

Your Go-To Hosting Resource

How to Install Nginx, MySQL, PHP (LEMP Stack) on Ubuntu 24.04?

To install a LEMP stack on Ubuntu 24.04, install Nginx (sudo apt install nginx -y), MySQL (sudo apt install mysql-server -y), and PHP 8.4 with FPM (sudo apt install php8.4 php8.4-fpm php8.4-mysql -y), then configure Nginx to pass .php requests to PHP-FPM via its Unix socket. Secure the stack with UFW and a free Let’s Encrypt SSL certificate. Full setup takes about 15–20 minutes.

Introduction

Setting up a LEMP stack, which includes Linux, Nginx, MySQL, and PHP, is a foundational step for hosting modern, dynamic web applications. This stack provides a powerful, open-source platform that’s lightweight, efficient, and widely supported across the web hosting industry.

Ubuntu with its long-term support and up-to-date packages, is an excellent choice for deploying the LEMP stack. By combining the speed of the Nginx web server with the reliability of MySQL and the flexibility of PHP, developers can build and scale robust web applications with ease.

In this guide, you’ll learn how to install and configure each component of the LEMP stack on an Ubuntu 24.04 server. We’ll walk through setting up a sample PHP application, connecting it to a MySQL database, and securing the server with an SSL certificate from Let’s Encrypt, ensuring your site is ready for production.

Prerequisites

Before getting started:

  • Set up an Ubuntu 24.04 server on Cantech.
  • Create an A record for your domain (e.g., app.example.com) pointing to your server’s public IP.
  • Connect via SSH as a non-root user with sudo privileges.
  • Update your server packages:
sudo apt update
sudo apt upgrade -y

Step 1: Install Nginx Web Server

➞ Install Nginx web server to host fast, secure websites on Ubuntu the first step in any Ubuntu PHP Nginx installation.

sudo apt install nginx -y

➞ Once the installation is complete, enable Nginx to start automatically at system boot using the command below.

sudo systemctl enable nginx

➞ Next, start the Nginx service using the following command:

sudo systemctl start nginx

➞ Verify Nginx status:

sudo systemctl status nginx

You should see output confirming that the service is active and running.

● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2025-10-15 10:24:17 UTC; 5min ago
       Docs: man:nginx(8)
   Main PID: 1245 (nginx)
      Tasks: 3 (limit: 1152)
     Memory: 5.8M
        CPU: 110ms
     CGroup: /system.slice/nginx.service
             ├─1245 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             ├─1246 nginx: worker process
             └─1247 nginx: worker process

Step 2: Installing MySQL

➞ With Nginx running, the next step is adding the database layer – install the latest MySQL server to complete the Nginx MySQL pairing.

sudo apt install mysql-server -y

➞ Start running the MySQL service.

sudo systemctl start mysql

➞ Enable the MySQL service to automatically start on system boot.

sudo systemctl enable mysql

➞ Verify MySQL status:

sudo systemctl status mysql

Output:

● mysql.service - MySQL Community Server
     Loaded: loaded (/lib/systemd/system/mysql.service; enabled; preset: enabled)
     Active: active (running) since Wed 2025-10-15 11:25:43 UTC; 1min 32s ago
   Main PID: 1432 (mysqld)
     Status: "Server is operational"
      Tasks: 38 (limit: 9442)
     Memory: 364.8M
        CPU: 1.482s
     CGroup: /system.slice/mysql.service
             └─1432 /usr/sbin/mysqld

➞ Run the MySQL secure installation tool to remove unsafe default settings and improve your database security.

sudo mysql_secure_installation

Recommended prompts:

  • Enable the VALIDATE PASSWORD plugin.
  • Choose STRONG policy (2).
  • Remove anonymous users.
  • Disallow remote root login.
  • Remove the test database.
  • Reload privilege tables.

➞ Open the MySQL console and create a new password for the root user.

sudo mysql

➞ Set a strong password and update authentication method:

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_secure_password';

➞ Refresh the MySQL privilege tables to make the changes effective.

mysql> FLUSH PRIVILEGES;

➞ Leave the MySQL console.

mysql> exit

➞ Restart MySQL:

sudo systemctl restart mysql

Step 3: Installing PHP

➞ To finish the Nginx PHP MySQL stack, Ubuntu 24.04 includes PHP 8.4 in its repository, offering slight performance improvements over PHP 8.3.

sudo apt install php8.4 php8.4-fpm php8.4-mysql php8.4-cli -y

The above command installs the following PHP modules:

  • php-mysql: Allows PHP to communicate with the MySQL database and execute SQL queries.
  • php-cli: Provides the PHP Command Line Interface (CLI) to run PHP scripts directly from the terminal.

➞ Verify PHP version:

php -v

Output:

PHP 8.4.0 (cli) (built: Sep 23 2024 10:15:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v8.4.0, Copyright (c), by Zend Technologies

➞ Start the PHP-FPM service for your installed version, such as PHP 8.4.

sudo systemctl start php8.4-fpm

➞ Set PHP-FPM to automatically start when the system boots.

sudo systemctl enable php8.4-fpm

➞ Check the PHP-FPM service status to make sure it’s running properly.

sudo systemctl status php8.4-fpm

Output:

● php8.4-fpm.service - The PHP 8.4 FastCGI Process Manager
     Loaded: loaded (/lib/systemd/system/php8.4-fpm.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2025-10-15 10:25:47 UTC; 2min ago
       Docs: man:php-fpm8.4(8)
   Main PID: 15234 (php-fpm8.4)
     Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
      Tasks: 3 (limit: 1112)
     Memory: 8.3M
        CPU: 95ms
     CGroup: /system.slice/php8.4-fpm.service
             ├─15234 php-fpm: master process (/etc/php/8.4/fpm/php-fpm.conf)
             ├─15235 php-fpm: pool www
             └─15236 php-fpm: pool www

Step 4: Configure PHP-FPM

➞ Before connecting Nginx and PHP, confirm PHP-FPM is listening on the correct socket – this is the bridge in any Nginx PHP Ubuntu configuration. Check the PHP-FPM Unix socket path using the ss command.

ss -pl | grep php

Output:

u_str LISTEN 0      128    /run/php/php8.4-fpm.sock  12345  *  1234/php-fpm: master
  • /run/php/php8.4-fpm.sock:  Shows the PHP-FPM socket path.

  • php-fpm: master: Indicates the PHP-FPM master process is active and listening.

➞ Navigate to PHP-FPM pool config directory:

sudo cd /etc/php/8.4/fpm/pool.d/

➞ Open the default PHP-FPM pool configuration file www.conf in a text editor like Nano.

sudo nano /etc/php/8.4/fpm/pool.d/www.conf

➞ Check the PHP-FPM pool name to confirm it’s correctly configured.

[www]

➞ Check that PHP-FPM runs under the www-data user.

user = www-data
group = www-data

Save and close the file.
➞ Adjust process manager settings if needed:

  • pm.max_children = 10
  • pm.start_servers = 4
  • pm.min_spare_servers = 2
  • pm.max_spare_servers = 6
  • pm.max_requests = 500

You can adjust the PHP-FPM pool settings based on your server’s specs and resources.

Step 5: Configure Nginx to Use PHP-FPM

➞ Now connect the two – this step handles the core Ubuntu Nginx PHP integration by telling Nginx to pass .php requests to PHP-FPM. Start by creating an index.php file inside your web root directory /var/www/html.

sudo touch /var/www/html/index.php

➞ Use the below command to insert PHP info content into the file.

echo "<?php phpinfo(); >" > sudo /var/www/html/index.php

➞ Delete default Nginx configuration file:

sudo rm /etc/nginx/sites-enabled/default
sudo rm /etc/nginx/sites-available/default

➞ Create a new server block:

sudo nano /etc/nginx/sites-available/app.example.com.conf

➞ Add the following configuration:

server {
    listen 80;
    server_name app.example.com;
    root /var/www/html;
    index index.php index.html;
    location / {
        try_files $uri $uri/ =404;
    }
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
    }
}

Save and close the file.
➞ Enable the new Nginx configuration. Replace app.example.com with your actual domain name.

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/app.example.com

➞ Check the Nginx configuration to ensure there are no errors.

sudo nginx -t

Output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

➞ Restart Nginx to load the updated configuration settings.

sudo systemctl restart nginx

➞ Allow HTTP traffic through UFW:

sudo ufw allow 80/tcp

Visit http://app.example.com to confirm PHP is working.

Step 6: Secure Your Server with SSL

When setting up dynamic web applications with the LEMP stack, securing your server is essential. Make sure all components accept only internal requests on 127.0.0.1, while Nginx handles HTTP (port 80) and HTTPS (port 443) traffic. Follow the steps below to configure the UFW firewall and enable SSL certificates for secure connections.

Set Up Uncomplicated Firewall (UFW)

By default, Uncomplicated Firewall (UFW) is enabled and active on Ubuntu 24.04 Cantech servers. Use the steps below to set up UFW and permit connections to the Nginx web server.

➞ Display all available UFW application profiles.

sudo ufw app list

Output:

Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH

➞ Permit the Nginx Full profile to open HTTP Port 80 and HTTPS Port 443 through the firewall.

sudo ufw allow 'Nginx Full'

➞ Restart UFW to implement the firewall modifications.

sudo ufw reload

➞ Check the firewall status to confirm that the new rules are active.

sudo ufw status

Output:

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Create Let’s Encrypt SSL Certificates

➞ Set up the Certbot Let’s Encrypt client plugin for Nginx.

sudo apt install python3-certbot-nginx -y

➞ Obtain and configure the SSL certificate:

sudo certbot --nginx --agree-tos --redirect --email [email protected] -d app.example.com

➞ Test auto-renewal:

sudo certbot renew --dry-run

➞ Restart Nginx:

sudo systemctl restart nginx

Step 7: Test the LEMP Stack with a Sample App

Nginx, MySQL, and PHP (LEMP) work together seamlessly to provide dynamic content for your web applications. Use the steps below to configure a sample application that shows a ‘Greetings from Cantech‘ message retrieved from a MySQL database on your server.
➞ Access MySQL using the root user account

mysql -u root -p

Use the root user password you previously configured to log into the MySQL console.
➞ Set up a new sample database named cantech_db

mysql> CREATE DATABASE cantech_db;

➞ Select the database for use.

mysql> USE cantech_db;

➞ Set up a new database user named db_user with a secure password.

mysql> CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'strong-password';

➞ Assign full permissions to the user for the cantech_db database.

mysql> GRANT ALL PRIVILEGES ON cantech_db. TO 'db_user'@'localhost';

➞ Refresh the MySQL privileges table to implement the new user modifications.

mysql> FLUSH PRIVILEGES;

➞ Set up a new table named CantechDocs with two columns: an id column serving as the primary key and a message column to store VARCHAR strings.

mysql> CREATE TABLE IF NOT EXISTS CantechDocs (id INT AUTO_INCREMENT PRIMARY KEY,  message VARCHAR(255) NOT NULL);

➞ Add a new entry to the message column in the CantechDocs table with the text Greetings from Cantech.

mysql> INSERT INTO CantechDocs (message) VALUES ('Greetings from Cantech');

➞ Check the table data to confirm that the new string has been added.

mysql> SELECT * from CantechDocs;

Output:

+----+------------------------+
| id | message                |
+----+------------------------+
|  1 | Greetings from Cantech |
+----+------------------------+
1 row in set (0.00 sec)

➞ Close the MySQL console.

mysql> exit;

➞ Generate a new test.php file in the /var/www/html/ web root directory using a text editor like Nano.

sudo nano /var/www/html/test.php

➞ Insert the following content into the file.

<?php
$servername = "localhost";
$username = "db_user";
$password = "strong-password";
$dbname = "cantech_db";
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
    die("Database Connection Failed: " . $conn->connect_error);
}
$sql = "SELECT message FROM CantechDocs";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
    $row = $result->fetch_assoc();
    echo "<h1>" . htmlspecialchars($row["message"]) . "</h1>";
} else {
    echo "<h1>No message found.</h1>";
}
$conn->close();
?>

Save and exit.

The PHP application code above establishes a connection to your MySQL database and shows the Greetings from Cantech string from your sample cantech_db database upon successful connection.

➞ Open your domain in a new browser window using the /test.php path.

https://app.example.com/test.php

You should see:
Greetings from Cantech

Conclusion

You’ve successfully installed, configured, and secured a LEMP stack Ubuntu 24.04. With Nginx serving as the web server, MySQL managing your databases, and PHP powering dynamic content, your server is now ready to host modern web applications. Secure your stack further with strong passwords, UFW rules, and regular updates.

FAQs

What is a LEMP stack?

LEMP stands for Linux, Nginx, MySQL, and PHP, a software stack used to run dynamic websites and web applications. It’s a lightweight, high-performance alternative to the traditional LAMP stack, with Nginx replacing Apache as the web server for better handling of concurrent connections.

Which PHP version does Ubuntu 24.04 install by default?

Ubuntu 24.04’s default repository ships PHP 8.4, which offers performance improvements over PHP 8.3. You can install it along with FPM and MySQL extensions using sudo apt install php8.4 php8.4-fpm php8.4-mysql -y.

Why is Nginx not showing my PHP page?

This is usually caused by a missing or misconfigured location ~ \.php$ block in your Nginx server config, or Nginx not pointing to the correct PHP-FPM socket path. Run sudo nginx -t to check for config errors, then restart Nginx.

Do I need a domain name to set up LEMP on Ubuntu?

No, you can test locally using your server’s IP address. A domain is only required to issue a Let’s Encrypt SSL certificate and to run the sample app in this guide with a proper server name.

Is UFW enabled by default on Ubuntu 24.04?

Yes, on Cantech Ubuntu 24.04 servers, UFW is enabled by default. You need to explicitly allow the Nginx Full profile to permit HTTP and HTTPS traffic.

How do I renew my Let’s Encrypt SSL certificate?

Certbot sets up auto-renewal by default. You can test that it’s working with sudo certbot renew --dry-run – no manual renewal is needed unless the dry run fails.

Related:

August 29, 2026