How to Install Apache, MySQL, PHP (LAMP Stack) on Debian 12

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

Introduction

The Linux, Apache, MySQL, and PHP (LAMP) stack is a collection of open-source applications that enable the development and deployment of dynamic web applications on a server. Linux runs as the base operating system while Apache works as a webserver to handle web requests. MySQL functions as a backend database and PHP processes dynamic web application contents.

This article explains how to install the LAMP stack on a Debian 12 server.

Prerequisites

Before you begin:

Install Apache Webserver

Apache is available in the default package repositories on Debian 12. Follow the steps below to install the Apache on your server.

  1. Install the Apache webserver.

    console
    $ sudo apt install apache2 -y
    
  2. View the installed Apache version on your server..

    console
    $ sudo apachectl -v
    

    Your output should be similar to the one below.

    Server version: Apache/2.4.61 (Debian)
    Server built:   2024-07-07T12:08:26
  3. Start the Apache service.

    console
    $ sudo systemctl start apache2
    
  4. Enable the Apache service to start automatically at boot.

    console
    $ sudo systemctl enable apache2
    
  5. View the Apache service status and verify that it's running on your server.

    console
    $ sudo systemctl status apache2
    

    Your output should be similar to the one below.

    ● apache2.service - The Apache HTTP Server
         Loaded: loaded (/lib/systemd/system/apache2.service; enabled; preset: enabled)
         Active: active (running) since Tue 2024-08-13 19:51:19 UTC; 1min 46s ago
           Docs: https://httpd.apache.org/docs/2.4/
       Main PID: 3080 (apache2)
          Tasks: 55 (limit: 2299)
         Memory: 9.6M
            CPU: 29ms
         CGroup: /system.slice/apache2.service
                 ├─3080 /usr/sbin/apache2 -k start
                 ├─3083 /usr/sbin/apache2 -k start
                 └─3084 /usr/sbin/apache2 -k start

Install MySQL

MySQL is not available in the Debian 12 package repositories by default. Follow the steps below to add the MySQL APT repository information to your server and install the latest database server package.

  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 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. Press Up and Down to select your preferred MySQL Server version and press Enter to proceed. 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 Down, 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 information index to apply the new MySQL package repository 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 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. Start the MySQL system service.

    console
    $ sudo systemctl start mysql
    
  10. Enable MySQL to start at boot.

    console
    $ sudo systemctl enable 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 your preferred password strength policy for your MySQL database server. For example, enter 2 to enable strong password validation.

      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 from MySQL.

      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

PHP is available in the default package repositories on Debian 12. Follow the steps below to install PHP, PHP-FPM, and additional 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 libapache2-mod-php -y
    

    The above command installs the following PHP modules:

    • php-mysql: Connects PHP to the MySQL database server to perform SQL operations.
    • php-cli: Allows you to run PHP scripts from the Command Line Interface (CLI).
    • libapache2-mod-php: Integrates PHP with the Apache webserver to enable processing and forwarding of PHP requests.
  3. View the PHP version installed 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 PHP version such as PHP 8.2.

    console
    $ sudo systemctl start php8.2-fpm
    
  5. Enable PHP-FPM to start automatically at 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 designed to handle 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. Enable the Apache FastCGI module proxy_fcgi to allow the webserver to communicate with PHP-FPM.

    console
    $ sudo a2enmod proxy_fcgi
    
  2. Use the ss utility to verify the active PHP-FPM Unix socket path.

    console
    $ ss -pl | grep php
    

    Your output should be similar to the one below.

    u_str LISTEN 0      4096                     /run/php/php8.2-fpm.sock 45907                         * 0

    Based on the above output, /run/php/php8.2-fpm.sock is the active PHP-FPM Unix socket path.

  3. Enable Apache's default PHP-FPM configuration for PHP version 8.2.

    console
    $ sudo a2enconf php8.2-fpm
    
  4. Restart the Apache webserver to apply the new configuration changes.

    console
    $ sudo systemctl restart apache2
    
  5. Open the default PHP-FPM pool configuration www.conf 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 is 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 pool configurations and modify them 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 that can 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, then some child processes will be 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, then the excess idle child processes are stopped.

      Save and close the file.

  6. Restart the PHP-FPM service to apply the new changes.

    console
    $ sudo systemctl restart php8.2-fpm
    

Configure Apache With PHP-FPM

PHP-FPM (FastCGI Process Manager) connects with Apache using the proxy_fcgi module and the PHP-FPM Unix socket. The proxy_fcgi module forwards requests to the PHP-FPM service which processes PHP scripts and returns the output to the webserver. Follow the steps below to configure Apache with PHP-FPM to serve dynamic web application files on the server.

  1. Create a new Apache virtual host configuration file using a text editor like nano. For example, website.conf.

    console
    $ sudo nano /etc/apache2/sites-available/website.conf
    
  2. Add the following configurations to the file. Replace app.example.com with your actual domain name and webmaster@app.example.com with your administrative email.

    apacheconf
    <VirtualHost *:80>
        ServerAdmin webmaster@app.example.com
        ServerName app.example.com
    
        DocumentRoot /var/www/html
        DirectoryIndex index.html index.php
    
        <Directory /var/www/html>
            Options Indexes FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>
    
        <FilesMatch \.php$>
            SetHandler "proxy:unix:/run/php/php8.2-fpm.sock|fcgi://localhost/"
        </FilesMatch>
    
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    

    The above Apache configuration creates a new virtual host that serves web application files from the web root directory /var/www/html/ using your app.example.com domain. Within the configuration:

    • <VirtualHost *:80>: Defines the virtual host to listen for connections on the HTTP port 80.
    • ServerAdmin webmaster@app.example.com: Sets the webserver administrator's email for receiving critical error notifications and alerts.
    • ServerName app.example.com: Specifies the virtual host domain to deliver web applications..
    • DocumentRoot /var/www/html/: Sets the virtual host's root directory.
    • DirectoryIndex index.html index.php: Sets a list of files to look for when an HTTP client requests an index for the virtual host.
    • <Directory /var/www/html/>: Sets the directory configurations for requests made to the /var/www/html directory.
    • Options Indexes FollowSymLinks: Allows directory listing and the use of symbolic links within the directory.
    • AllowOverride All: Permits .htaccess files to override the settings in the virtual host configuration.
    • Require all granted: Grants all users access to files in the web root directory.
    • <FilesMatch \.php$>: Instructs Apache how to handle PHP files. The SetHandler directive specifies that PHP files should be processed by PHP-FPM using the specified Unix socket.
    • SetHandler "proxy:unix:/var/run/php/php8.2-fpm.sock|fcgi://localhost/": Enables Apache to connect to PHP-FPM and process PHP files using the Unix socket path /var/run/php/php8.2-fpm.sock.
    • ErrorLog ${APACHE_LOG_DIR}/error.log: Specifies the virtual host error log filename and location.
    • CustomLog ${APACHE_LOG_DIR}/access.log combined: Specifies the virtual host's access log file location and writes data in the combined log format.
  3. Disable the default Apache virtual host configuration file.

    console
    $ sudo a2dissite 000-default
    
  4. Enable the new Apache virtual host configuration file.

    console
    $ sudo a2ensite website
    
  5. Test the new Apache configuration for errors.

    console
    $ sudo apachectl configtest
    

    Output:

    Syntax OK
  6. Restart the Apache webserver to apply your configuration changes.

    console
    $ sudo systemctl restart apache2
    
  7. Allow the HTTP port 80 through the firewall.

    console
    $ sudo ufw allow 80/tcp
    
  8. Reload UFW to apply the firewall changes.

    console
    $ sudo ufw reload
    
  9. Create a new index.php file in your web root directory /var/www/html.

    console
    $ sudo touch /var/www/html/index.php
    
  10. Run the following command to add PHP information contents to the file.

    console
    $ echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/index.php
    
  11. Access the /index.php path in your web browser and verify that your PHP information displays.

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

    PHP information Page

Secure Apache Webserver

Apache delivers dynamic web applications on the HTTP port 80 by default which enables unencrypted traffic to the server. Generate SSL certificates to enable HTTPS connections on port 443 and allow all Apache network ports through the default firewall configuration as described in the following sections.

Configure Uncomplicated Firewall (UFW)

Uncomplicated Firewall (UFW) is available and active on Vultr Debian 12 servers by default. Follow the steps below to configure UFW and allow connections to the Apache webserver.

  1. Allow HTTP connections on port 80.

    console
    $ sudo ufw allow 443/tcp
    
  2. Allow HTTPS connections on port 443.

    console
    $ sudo ufw allow 443/tcp
    
  3. Reload UFW to apply the firewall changes.

    console
    $ sudo ufw reload
    
  4. View the firewall status and verify the new rules are available.

    console
    $ sudo ufw status
    

    Output:

    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW       Anywhere
    80/tcp                     ALLOW       Anywhere
    443/tcp                    ALLOW       Anywhere
    22/tcp (v6)                ALLOW       Anywhere (v6)
    80/tcp (v6)                ALLOW       Anywhere (v6)
    443/tcp (v6)               ALLOW       Anywhere (v6)

Generate Let's Encrypt SSL Certificates

  1. Install the Certbot Let's Encrypt client plugin for Apache.

    console
    $ sudo apt install certbot python3-certbot-apache
    
  2. Request a new Let's Encrypt SSL certificate on your server. Replace app.example.com with your domain and email@example.com with your actual email address.

    console
    $ sudo certbot --apache --agree-tos --redirect --email email@example.com -d app.example.com
    
  3. Test the Certbot SSL certificate renewal process.

    console
    $ sudo certbot renew --dry-run
    
  4. Restart Apache to apply the SSL configuration changes.

    console
    $ sudo systemctl restart apache2
    

Test the Installation

Follow the steps below to set up sample web applications, create a database table, and insert a new Greetings from Vultr record into the table. Then, connect to the database and fetch the Greetings from Vultr message from the MySQL database on your server.

  1. Log in to MySQL as root.

    console
    $ mysql -u root -p
    

    Enter the root user password you set earlier when prompted to access the MySQL console.

  2. Create a new sample database. For example, VultrDB.

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

    sql
    mysql> USE VultrDB;
    
  4. Create a new sample database user db_user with a strong password. Replace Str0ng_P@ssw0rd! with your desired password.

    sql
    mysql> CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'Str0ng_P@ssw0rd!';
    
  5. Grant db_user full privileges to the VultrDB database.

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

    sql
    mysql> FLUSH PRIVILEGES;
    
  7. Exit the MySQL console.

    sql
    mysql> exit;
    
  8. Create a new insert.php PHP file in your web root directory.

    console
    $ sudo nano /var/www/html/insert.php
    
  9. Add the following contents to the file.

    php
    <?php
    // Database configuration
    $servername = "localhost";
    $username = "db_user";
    $password = "Str0ng_P@ssw0rd!";
    $dbname = "VultrDB";
    
    // Create a database connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    
    // Check the database connection
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }
    
    // Check if the VultrTable exists
    $tableName = "VultrTable";
    $tableCheckQuery = "SHOW TABLES LIKE '$tableName'";
    $result = $conn->query($tableCheckQuery);
    
    if ($result && $result->num_rows > 0) {
        echo "The Table '$tableName' already exists in the '$dbname' database.<br>";
    } else {
        // Create VultrTable table if it doesn't exist
        $tableCreateQuery = "CREATE TABLE $tableName (
            id INT(11) AUTO_INCREMENT PRIMARY KEY,
            greetings VARCHAR(255) NOT NULL
        )";
    
        if ($conn->query($tableCreateQuery) === TRUE) {
            echo "Table '$tableName' created successfully.<br>";
        } else {
            echo "Error creating table: " . $conn->error . "<br>";
        }
    }
    
    // Message to insert into the VultrTable
    $greetings = "Greetings from Vultr";
    
    // Prepare and bind
    $stmt = $conn->prepare("INSERT INTO VultrTable (greetings) VALUES (?)");
    $stmt->bind_param("s", $greetings);
    
    // Execute the statement
    if ($stmt->execute()) {
        echo "New record created successfully";
    } else {
        echo "Error: " . $stmt->error;
    }
    
    // Close connections
    $stmt->close();
    $conn->close();
    ?>
    

    Save and close the file.

    The above PHP application connects to the MySQL database server as db_user to create a new VultrTable table in the VultrDB database if it does not exist. The application then inserts a new Greetings from Vultr record into the table when the connection is successful.

  10. Create a new display.php application file in your web root directory.

    console
    $ sudo nano /var/www/html/display.php
    
  11. Add the following contents to the file.

    php
    <?php
    // Database configuration
    $servername = "localhost";
    $username = "db_user";
    $password = "Str0ng_P@ssw0rd!";
    $dbname = "VultrDB";
    
    // Create a database connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    
    // Check the database connection
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }
    
    // Query to select all entries from the VultrTable table.
    $sql = "SELECT * FROM VultrTable";
    $result = $conn->query($sql);
    
    if ($result->num_rows > 0) {
        // Display each row
        while ($row = $result->fetch_assoc()) {
            echo "<h1>" . $row["id"] . " : " . $row["greetings"] . "</h1> <br>";
        }
    } else {
        echo "0 results";
    }
    
    // Close connection
    $conn->close();
    ?>
    

    Save and close the file.

    The above PHP application fetches all records from the VultrTable table in the VultrDB sample database and displays the result when the connection is successful.

  12. Access the /insert.php path using your domain in a new browser window to create a new table and insert data.

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

    Create new Table and Insert Record

  13. Access the /display.php path using your domain in a new browser window to fetch all table records from the database.

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

    Greetings From Vultr Page

Conclusion

You have installed the Apache, MySQL, and PHP (LAMP) stack on your Debian 12 server. You can create and securely deploy multiple web applications using virtual host configurations and PHP-FPM pools on your server. For more information and configuration options, visit the following documentation resources.