Introduction
A LEMP stack is a group of open-source software that works together to serve dynamic websites and applications. The name LEMP stands for:
- Linux – the operating system
- Nginx (pronounced “Engine-X”) – the web server
- MySQL – the relational database management system
- PHP – the scripting language for dynamic content
Unlike the traditional LAMP stack that uses Apache, the LEMP stack replaces Apache with Nginx, a high-performance web server known for handling more concurrent connections while using fewer system resources. This makes it a popular choice for modern applications and high-traffic websites.
In this guide, you will learn how to install and configure the LEMP stack on Debian 12 (Bookworm)
Step 1 – Install Nginx
Nginx is a lightweight, high-performance web server that also works as a reverse proxy and load balancer. It is included in the default Debian 12 repositories, so installation is straightforward.
1. Install Nginx web server.
apt install nginx -y
2. Once installed, check the installed version.
nginx -v
Output.
nginx version: nginx/1.22.1
3. Enable Nginx to start automatically on system boot and start the service immediately.
systemctl enable nginx systemctl start nginx
4. Check the Nginx service status.
systemctl status nginx
Output.
● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled) Active: active (running) since Fri 2025-09-05 12:40:50 UTC; 14s ago Docs: man:nginx(8) Process: 1067 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 1068 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 1092 (nginx) Tasks: 3 (limit: 4642) Memory: 2.4M CPU: 28ms CGroup: /system.slice/nginx.service ├─1092 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;" ├─1095 "nginx: worker process" └─1096 "nginx: worker process"
Step 2 – Install MySQL
MySQL is a powerful relational database management system that stores and manages data for dynamic web applications. Since Debian 12 does not include MySQL in its default repositories, you’ll need to add the official MySQL APT repository before installing.
1. Download the MySQL APT repository configuration package.
wget https://dev.mysql.com/get/mysql-apt-config_0.8.34-1_all.deb
2. Install the downloaded package.
apt install ./mysql-apt-config_0.8.34-1_all.deb
During installation, you will see a configuration screen.
Select MySQL Server & Cluster option.
Use the arrow keys to select your preferred MySQL version (for example, mysql-8.4-lts).
Press Enter, then select Ok to save changes.
3. After adding the repository, update your package list.
apt update -y
4. Now install MySQL server.
apt install mysql-server -y
During installation, you will be prompted to set a password for the root database user. Enter a strong password and press Enter.
5. Check the installed version.
mysql --version
Output.
mysql Ver 8.4.6 for Linux on x86_64 (MySQL Community Server - GPL)
6. Start MySQL and enable it to run automatically on system boot.
systemctl enable mysql systemctl start mysql
7. Verify the MySQL service status.
systemctl status mysql
output.
● mysql.service - MySQL Community Server Loaded: loaded (/lib/systemd/system/mysql.service; enabled; preset: enabled) Active: active (running) since Fri 2025-09-05 12:44:43 UTC; 19s ago Docs: man:mysqld(8) http://dev.mysql.com/doc/refman/en/using-systemd.html Main PID: 2175 (mysqld) Status: "Server is operational" Tasks: 35 (limit: 4642) Memory: 427.5M CPU: 852ms CGroup: /system.slice/mysql.service └─2175 /usr/sbin/mysqld
8. Secure the MySQL installation.
mysql_secure_installation
Enter the root database user password you set earlier.
Enter password for user root:
Enter Y when prompted to setup the VALIDATE PASSWORD component.
VALIDATE PASSWORD COMPONENT can be used to test passwords and improve security. It checks the strength of password and allows the users to set only those passwords which are secure enough. 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.
Using existing password for root. Estimated strength of the password: 50 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.
Enter Y when prompted to disallow remote login for the root user.
Enter Y when prompted to remove the test database from your MySQL database server.
Enter Y to reload the MySQL privileges table and apply all configuration changes.
Step 3 – Install PHP and PHP-FPM
PHP is the scripting language that powers many dynamic applications such as WordPress, Laravel, and Drupal. Since Nginx does not process PHP code directly, we’ll install PHP-FPM (FastCGI Process Manager), which handles PHP execution and communicates with Nginx.
1. Install PHP and the PHP-FPM.
apt install php php-fpm -y
2. Install additional modules for MySQL database connectivity and command-line support.
apt install php-mysql php-cli -y
3. Check the installed version of PHP.
php -v
Output.
PHP 8.2.29 (cli) (built: Jul 3 2025 16:16:05) (NTS) Copyright (c) The PHP Group Zend Engine v4.2.29, Copyright (c) Zend Technologies with Zend OPcache v8.2.29, Copyright (c), by Zend Technologies
4. Start and enable the PHP-FPM server.
systemctl start php8.2-fpm systemctl enable php8.2-fpm
5. Verify that PHP-FPM is active and running.
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 Fri 2025-09-05 12:48:38 UTC; 22s ago Docs: man:php-fpm8.2(8) Process: 11802 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/8.2/fpm/pool.d/www.conf 82 (code=exited, status=0/SUCCESS) Main PID: 11799 (php-fpm8.2) Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0.00req/sec" Tasks: 3 (limit: 4642) Memory: 9.5M CPU: 71ms CGroup: /system.slice/php8.2-fpm.service ├─11799 "php-fpm: master process (/etc/php/8.2/fpm/php-fpm.conf)" ├─11800 "php-fpm: pool www" └─11801 "php-fpm: pool www"
Step 4 – Configure PHP-FPM
By default, PHP-FPM is configured to use the www-data user and group, which is also the default user Nginx runs under. To ensure compatibility, we’ll verify and adjust the PHP-FPM pool configuration.
1. Edit the PHP-FPM pool configuration file.
nano /etc/php/8.2/fpm/pool.d/www.conf
Find and ensure the following lines are set to www-data.
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.
listen = /run/php/php8.2-fpm.sock
Save and close the file.
2. Restart PHP-FPM to apply the changes.
systemctl restart php8.2-fpm
Step 5 – Configure Nginx With PHP-FPM
Now that PHP-FPM is running, we need to configure Nginx so it can pass PHP requests to PHP-FPM. This is done by creating a new server block (virtual host).
1. Create a new Nginx virtual host.
nano /etc/nginx/sites-available/lemp.example.com
Add the following lines:
server { listen 80; server_name lemp.example.com; root /var/www/lemp.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; } }
2. Create a symbolic link to enable the new site
ln -s /etc/nginx/sites-available/lemp.example.com /etc/nginx/sites-enabled/
3. Check Nginx for syntax errors.
nginx -t
Output.
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
4. Reload the Nginx service.
systemctl reload nginx
5. Create the document root for your site.
mkdir -p /var/www/lemp.example.com
6. Create a phpinfo.php file to test PHP processing.
nano /var/www/lemp.example.com/phpinfo.php
Add the below code.
<?php phpinfo(); ?>
7. Open your browser and visit the URL:
http://lemp.example.com/phpinfo.php
You should see the PHP information page, confirming that Nginx is correctly passing PHP requests to PHP-FPM.
Conclusion
In this tutorial, you set up a complete LEMP stack on Debian 12. You began by installing Nginx as the web server, then added MySQL to handle databases, and installed PHP with PHP-FPM to process dynamic content. After configuring PHP-FPM, you integrated it with Nginx by creating a server block and verified the setup with a phpinfo() test page.