How to Install Nginx, MySQL, PHP (LEMP Stack) on Debian 12

Updated on November 21, 2023
How to Install Nginx, MySQL, PHP (LEMP Stack) on Debian 12 header image

Introduction

Linux, Nginx, MySQL, and PHP (LEMP) Stack is a collection of open source applications that enable the development and deployment of web applications on a server. Linux works as the operating system, Nginx handles webserver functionalities, MySQL manages the database, and PHP processes dynamic web contents.

This article explains how to install the LEMP stack on Debian 12 to deliver dynamic web applications on the server.

Prerequisites

Before you begin:

Install Nginx

Nginx is available in the default package repositories on Debian 12. Follow the steps below to install Nginx using the APT package manager on your server.

  1. Install Nginx.

    console
    $ sudo apt install nginx -y
    
  2. Verify the installed Nginx version.

    console
    $ nginx -v
    

    Output:

    nginx version: nginx/1.22.1
  3. Enable Nginx to automatically start at boot.

    console
    $ sudo systemctl enable nginx
    
  4. Start the Nginx service.

    console
    $ sudo systemctl start nginx
    
  5. View the Nginx service status and verify that it's running.

    console
    $ sudo systemctl status nginx
    

    Output:

    nginx.service * A high performance webserver and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Fri 2024-08-09 06:59:07 UTC; 2min 4s ago
       Docs: man:nginx(8)
    Main PID: 1586 (nginx)
      Tasks: 2 (limit: 4637)
     Memory: 1.7M
        CPU: 11ms

Install MySQL

MySQL is not available in the default package repositories on Debian 12. Follow the steps below to add the MySQL repository information and install the database.

  1. Download the latest MySQL package repository setup file.

    console
    $ sudo wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb
    

    Visit the MySQL APT repository page to verify the latest Debian package file to download on your server.

  2. Run the file to install the latest MySQL repository information on your server.

    console
    $ sudo dpkg -i mysql-apt-config_0.8.32-1_all.deb
    
  3. Select the MySQL Server & Cluster option and press Enter when prompted.

    ┌─────────────────────────────────┤ Configuring mysql-apt-config ├─────────────────────────────────┐
    │ Which MySQL product do you wish to configure?                                                    │
    │                                                                                                  │
    │                   MySQL Server & Cluster (Currently selected: mysql-8.4-lts)                     │
    │                   MySQL Connectors (Currently selected: Enabled)                                 │
    │                   Ok                                                                             │
    │                                                                                                  │
    │                                              <Ok>                                                │
    └──────────────────────────────────────────────────────────────────────────────────────────────────┘
  4. Use Up and Down arrow keys to select your preferred MySQL server version and press Enter. For example, select mysql-8.4-lts version.

     ┌─────────────────────────────────┤ Configuring mysql-apt-config ├─────────────────────────────────┐
     │ Which server version do you wish to receive?                                                     │
     │                                                                                                  │
     │                                    mysql-8.0                                                     │
     │                                    mysql-innovation                                              │
     │                                    mysql-8.4-lts                                                 │
     │                                    mysql-cluster-8.0                                             │
     │                                    mysql-cluster-innovation                                      │
     │                                    mysql-cluster-8.4-lts                                         │
     │                                    None                                                          │
     │                                                                                                  │
     │                                              <Ok>                                                │
     └──────────────────────────────────────────────────────────────────────────────────────────────────┘
  5. Press the Down arrow key to select Ok and press Enter to save changes.

     ┌─────────────────────────────────┤ Configuring mysql-apt-config ├─────────────────────────────────┐
     │ Which MySQL product do you wish to configure?                                                    │
     │                                                                                                  │
     │                   MySQL Server & Cluster (Currently selected: mysql-8.4-lts)                     │
     │                   MySQL Connectors (Currently selected: Enabled)                                 │
     │                   Ok                                                                             │
     │                                                                                                  │
     │                                              <Ok>                                                │
     └──────────────────────────────────────────────────────────────────────────────────────────────────┘
  6. Update the server's package index to apply the new MySQL package information.

    console
    $ sudo apt update
    
  7. Install the MySQL database server package.

    console
    $ sudo apt install mysql-server -y
    
    • Enter a new root database user password when prompted and press Enter.

      Enter root password:
    • Enter the password again to validate it and press Enter to update the root database user.

      Re-enter root password:
  8. View the installed MySQL version on your server.

    console
    $ mysql --version
    

    Your output should be similar to the one below.

    mysql  Ver 8.4.2 for Linux on x86_64 (MySQL Community Server - GPL)
  9. Enable the MySQL service to automatically start at system boot.

    console
    $ sudo systemctl enable mysql
    
  10. Start the MySQL system service.

    console
    $ sudo systemctl start mysql
    
  11. View the MySQL service status and verify that it's running on your server.

    console
    $ sudo systemctl status mysql
    

    Your output should be similar to the one below.

    ● mysql.service - MySQL Community Server
         Loaded: loaded (/lib/systemd/system/mysql.service; enabled; preset: enabled)
         Active: active (running) since Tue 2024-08-13 20:20:56 UTC; 7min ago
           Docs: man:mysqld(8)
                 http://dev.mysql.com/doc/refman/en/using-systemd.html
       Main PID: 4331 (mysqld)
         Status: "Server is operational"
          Tasks: 35 (limit: 2299)
         Memory: 443.5M
            CPU: 1.924s
         CGroup: /system.slice/mysql.service
                 └─4331 /usr/sbin/mysqld
  12. Run the MySQL secure installation script to secure the database server.

    console
    $ sudo mysql_secure_installation
    
    • Enter the root database user password you set earlier and press Enter.

      Enter password for user root:
    • Enter Y when prompted to setup the VALIDATE PASSWORD component.

      Would you like to setup VALIDATE PASSWORD component?
      
      Press y|Y for Yes, any other key for No: Y
    • Set the preferred password strength policy for your MySQL database server. For example, enter 2 to enable the use of strong passwords on your server.

      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: 2
    • Enter N when prompted to change the root database user password, or enter Y to change the password.

      Change the password for root ? ((Press y|Y for Yes, any other key for No) : N
    • Enter Y when prompted to remove anonymous users on your MySQL database server.

      Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y
    • Enter Y when prompted to disallow remote login for the root user.

      Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y
    • Enter Y when prompted to remove the test database from your MySQL database server.

      Remove test database and access to it? (Press y|Y for Yes, any other key for No) : Y
    • Enter Y to reload the MySQL privileges table and apply all configuration changes.

      Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y

      Output:

      All done!

Install PHP and PHP-FPM

PHP is available in the default package repositories on Debian 12. Follow the steps below to install PHP, PHP-FPM, and recommended web application modules on your server.

  1. Install PHP and PHP-FPM.

    console
    $ sudo apt install php php-fpm -y
    
  2. Install PHP modules.

    console
    $ sudo apt install php-mysql php-cli -y
    

    The above command installs the following PHP modules:

    • php-mysql: Allows PHP to connect to the MySQL database server and perform SQL operations.
    • php-cli: Enables PHP scripts to run in your terminal session.
  3. View the installed PHP version on your server.

    console
    $ php -v
    

    Your output should be similar to the one below.

    PHP 8.2.20 (cli) (built: Jun 17 2024 13:33:14) (NTS)
    Copyright (c) The PHP Group
    Zend Engine v4.2.20, Copyright (c) Zend Technologies
        with Zend OPcache v8.2.20, Copyright (c), by Zend Technologies
  4. Start the PHP-FPM service depending on your installed PHP version. For example, PHP 8.2.

    console
    $ sudo systemctl start php8.2-fpm
    
  5. Enable PHP-FPM to start automatically at system boot.

    console
    $ sudo systemctl enable php8.2-fpm
    
  6. View the PHP-FPM service status and verify that it's running.

    console
    $ sudo systemctl status php8.2-fpm
    

    Output:

    ● php8.2-fpm.service - The PHP 8.2 FastCGI Process Manager
         Loaded: loaded (/lib/systemd/system/php8.2-fpm.service; enabled; preset: enabled)
         Active: active (running) since Tue 2024-08-13 20:40:54 UTC; 1min 52s ago
           Docs: man:php-fpm8.2(8)
       Main PID: 13661 (php-fpm8.2)
         Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0.00req/sec"
          Tasks: 3 (limit: 2299)
         Memory: 9.5M
            CPU: 31ms
         CGroup: /system.slice/php8.2-fpm.service
                 ├─13661 "php-fpm: master process (/etc/php/8.2/fpm/php-fpm.conf)"
                 ├─13662 "php-fpm: pool www"
                 └─13663 "php-fpm: pool www"

Configure PHP-FPM

PHP-FPM (FastCGI Process Manager) is a process manager for PHP that handles webserver requests for dynamic PHP applications. PHP-FPM offers several enhancements, including process management, server-specific configuration, and improved performance. Follow the steps below to configure PHP-FPM on your server.

  1. Open the default PHP-FPM pool www.conf configuration using a text editor such as nano.

    console
    $ sudo nano /etc/php/8.2/fpm/pool.d/www.conf
    
    • View the PHP-FPM pool name and verify that it's set to www.

      ini
      [www]
      
    • Find the following directives and verify that the values are set to www-data.

      ini
      user = www-data
      group = www-data
      listen.owner = www-data
      listen.group = www-data
      
    • Find the listen directive and verify that it is set to the PHP-FPM unix socket path /run/php/php8.2-fpm.sock.

      ini
      listen = /run/php/php8.2-fpm.sock
      
    • Find the following directives and modify the values depending on your server specifications and available resources.

      • pm: Specifies the process manager type. The dynamic value allows PHP child processes to adjust automatically based on server needs.
      • pm.max_children: Defines the maximum number of PHP child processes to run simultaneously.
      • pm.start_servers: Sets the number of child processes created on startup, providing an initial pool to handle requests.
      • pm.min_spare_servers: Sets the minimum number of idle child processes. If the number of idle processes is less than the specified value, new child processes are created.
      • pm.max_spare_servers: Sets the maximum number of idle child processes allowed. If the number of idle child processes exceeds the specified value, the excess idle child processes are stopped.

    Save and close the file.

  2. Restart the PHP-FPM service to apply your configuration changes.

    console
    $ sudo systemctl restart php8.2-fpm
    

Configure Nginx With PHP-FPM

Follow the steps below to configure Nginx to process PHP scripts by creating a new virtual host configuration that connects to the PHP-FPM service to process dynamic application requests.

  1. Create a new virtual host configuration file in the /etc/nginx/sites-available/ directory.

    console
    $ sudo nano /etc/nginx/sites-available/app.example.com
    
  2. Add the following contents to the file. Replace app.example.com with your actual domain.

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

    Save and close the file.

    The above Nginx configuration creates a new virtual host that listens for connections using the app.example.com domain and delivers web application files from the /var/www/app.example.com directory. All PHP file requests are forwarded to the /var/run/php/php-fpm.sock PHP-FPM Unix socket for processing.

  3. Create a new symbolic link to the /etc/nginx/sites-enabled/ directory to activate the virtual host configuration.

    console
    $ sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
    
  4. Test the Nginx configuration for errors.

    console
    $ 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
  5. Reload Nginx to apply the configuration changes.

    console
    $ sudo systemctl reload nginx
    
  6. Create a new web root directory to store your web application files.

    console
    $ sudo mkdir -p /var/www/app.example.com
    
  7. Create a new phpinfo.php web application file in the directory.

    console
    $ sudo nano /var/www/app.example.com/phpinfo.php
    
  8. Add the following contents to the file.

    php
    <?php
    phpinfo();
    ?>
    

    Save and close the file.

    The above application displays the PHP information on your server when accessed using your virtual host's domain.

  9. Allow HTTP connections through the firewall.

    console
    $ sudo ufw allow 80/tcp
    
  10. Reload UFW to apply changes.

    console
    $ sudo ufw reload
    
  11. Access the /phpinfo domain path using a web browser such as Chrome.

    http://app.example.com/phpinfo.php

    Test access to the Nginx Virtual Host Application

Set Up Firewall Rules

Uncomplicated Firewall (UFW) is active and available on Vultr Debian servers by default. Follow the steps below to allow connections to the HTTP and HTTPS ports to enable Nginx deliver web application on the server.

  1. View the UFW status and verify that it's active.

    console
    $ sudo ufw status
    

    Output:

    Status: active
  2. Allow HTTP and HTTPS connections on the server using the Nginx Full service profile.

    console
    $ sudo ufw allow 'Nginx Full'
    
  3. View the UFW status and verify that the new rules are available.

    console
    $ sudo ufw status
    

    Output:

    Status: active
    
    To                         Action      From
    -*                         -----*      ----
    Nginx Full                 ALLOW       Anywhere
    Nginx Full (v6)            ALLOW       Anywhere (v6)

Test the LEMP Stack Installation

Nginx processes HTTP requests and forwards them to PHP-FPM for handling. The php-mysql extension connects PHP to the MySQL database, enabling data retrieval and storage. Follow these steps to create a PHP application that displays a 'Greetings from Vultr' message retrieved from your MySQL database.

  1. Log in to the MySQL database server as the root database user.

    console
    $ mysql -u root -p
    
  2. Create a new test_db database.

    sql
    mysql> CREATE DATABASE test_db;
    
  3. Switch to the test_db database.

    sql
    mysql> USE test_db;
    
  4. Create a new sample database user test_user with a strong password. Replace Strong)P@ssword123 with your desired password.

    sql
    mysql> CREATE USER 'test_user'@'localhost' IDENTIFIED BY 'Strong)P@ssword123';
    
  5. Grant the user full privileges to the test_db database.

    sql
    mysql> GRANT ALL PRIVILEGES ON test_db.* TO 'test_user'@'localhost';
    
  6. Reload the MySQL privileges table to apply changes.

    sql
    mysql> FLUSH PRIVILEGES;
    
  7. Create a new greetings table with two columns: id (for numeric data) and message (for text):

    sql
    mysql> CREATE TABLE greetings (id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255) NOT NULL);
    
  8. Insert a Greetings from Vultr record into the greetings table.

    sql
    mysql> INSERT INTO greetings (message) VALUES ('Greetings from Vultr');
    
  9. Query the greetings table to verify that the records are available.

    sql
    mysql> SELECT * FROM greetings;
    

    Output:

    +----+----------------------+
    | id | message              |
    +----+----------------------+
    |  1 | Greetings from Vultr |
    +----+----------------------+
  10. Exit the MySQL console.

    sql
    EXIT;
    
  11. Create a new PHP application file greetings.php in your /var/www/app.example.com/ web root directory.

    console
    $ sudo nano /var/www/app.example.com/greetings.php
    
  12. Add the following contents to the file.

    php
    <?php
    $servername = "localhost";
    $username = "test_user";
    $password = "Strong)P@ssword123";
    $dbname = "test_db";
    
    // Create database connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    
    // Check database connection
    if ($conn->connect_error) {
        die("Database Connection Failed: " . $conn->connect_error);
    }
    
    // Retrieve the record from greetings Table
    $sql = "SELECT message FROM greetings";
    $result = $conn->query($sql);
    
    if ($result->num_rows > 0) {
        $row = $result->fetch_assoc();
        echo "<h1 align='center'>" . $row["message"]. "</h1>";
    } else {
        echo "<h1 align='center'>No message found.</h1>";
    }
    
    $conn->close();
    ?>
    

    Save and close the file.

    The above application code displays a Greetings from Vultr message from the MySQL database when accessed using your virtual host's domain.

  13. Access the /greetings.php domain path to test access to the PHP application.

    http://app.example.com/greetings.php

    Sample Greetings from Vultr Application on a Debian 12 Server

Conclusion

You have installed the LEMP stack on your Debian 12 server. You set up Nginx as the webserver, MySQL as the database backend, and PHP with PHP-FPM to process dynamic web application contents. For more information and configuration options for each application within the stack, visit the following resources.