Debian LEMP stack

There is a lot of guides how to configure Nginx, MariaDB and PHP on Linux. A lot of them is outdated. Probably someday this one get out of date too… no wait! This one will be different, always fresh!

No matter what version of Debian you use, your Nginx, MariaDB and PHP (8.1) will be always up to date.

Lemp Stack

I will not argue my decision about such and no other configuration, I just like Nginx and MariaDB. Rather, I will focus on showing the configuration that will allow us to use the latest versions of each program. Most applications from the official repositories of a given distribution are not in the latest version. Of course, this is due to the desire to maintain stability. Personally, I use the solution described in this article and never complained about errors or instability. However, before you implement such a solution, or try to update an existing infrastructure, first make sure that everything goes smooth in the test environment. The fact that it works for me does not mean that it will also work for you :)

Install necessary packages:

1
sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring

Repositories. It’a all about repositories. Before you set up new repository for your server, you need to know what version of Debian you are using. The codename. To check codename use command below:

1
sudo lsb_release -sc

To see more info about your system you can use:

1
sudo lsb_release -a

Example result of command:

1
2
3
4
Distributor ID:	Debian
Description: Debian GNU/Linux 12 (bookworm)
Release: 12
Codename: bookworm

As you now know the codename of your server you can use the codename name in the configuration below.

Nginx

Download signing key. For any config files changes use your favorite editor. Mine is nano. You can find latest official Nginx repos here.

1
2
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

add it:

1
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg

add official stable Nginx repository:

1
2
3
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

If you would like to use mainline Nginx packages, run the following command instead:

1
2
3
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

Now you can update package list and install latest version of Nginx:

1
sudo apt update && sudo apt install nginx

Congrats, you have latest version of Nginx!

Clean Nginx from official repo is not tweaked as Debian prepared version called nginx-full. You will need to spend some time to configure it.

PHP

Similar steps like above.

Add repository:

1
sudo sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'

Download and add repository key:

1
sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg

Update package list and install PHP 8.2-fpm:

1
sudo apt update && sudo apt install php8.2-fpm

and then PHP itself:

1
sudo apt install php8.2

It is also worth to setup repository pining to make sure you are installing from official source and not default Debian repo:

1
2
echo -e "Package: php*\nPin: origin packages.sury.org\nPin-Priority: 900\n" \
| sudo tee /etc/apt/preferences.d/99php

This will make packages.sury.org priority.

To chek you php version run:

1
sudo php -v

You may also be interested in additional PHP modules, like for WordPress:

1
sudo apt install php-bcmath php-curl php-gd php-imagick php-intl php-json php-mcrypt php-mysql php-ssh2 php-xml php-zip php-apcu php-mbstring php-soap php-igbinary php-memcached

Congrats, you have latest version of PHP 8.2!

MariaDB

Before you install latest MariaDB you need to check for repository on MariaDB repository page.

Go to page, choose your Linux Distribution, Release/Codename and then mirror.

Install required package:

1
sudo apt install apt-transport-https curl

Add repository key:

1
2
sudo mkdir -p /etc/apt/keyrings
sudo curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'

Add repository to your source.list

1
sudo nano /etc/apt/sources.list.d/mariadb.sources

File should contain:

1
2
3
4
5
6
7
8
9
10
# MariaDB 10.11 repository list - created 2023-07-30 13:57 UTC
# https://mariadb.org/download/
X-Repolib-Name: MariaDB
Types: deb
# deb.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details.
# URIs: https://deb.mariadb.org/10.11/debian
URIs: https://ftp.bme.hu/pub/mirrors/mariadb/repo/10.11/debian
Suites: sid
Components: main
Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp

Update package list and install MariaDB:

1
sudo apt update && sudo apt install mariadb-server mariadb-client mariadb-backup

After all configure it using wizard:

1
sudo mariadb-secure-installation

Congrats, you have latest version of MariaDB!

Extra steps

Additional steps worth to make. Additional information.

SSL

You may be interested to add free Let’s Encrypt certificate, to make communication with your web server secure. Check my guide how to do that: Let’s Encrypt SSL Cert for Nginx

Nginx configuration

Nginx configuration adjust:

1
sudo nano /etc/nginx/nginx.conf

Edit/add line:

1
keepalive_timeout 2;

Sometimes after installation or restarting Nginx you can get error like this:

1
Starting nginx: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)

Fix it using this command:

1
sudo fuser -k 80/tcp

PHP FPM

If php-fpm (alternative for PHP FastCGI) is your favorite process manager for PHP, edit your website configuration:

1
sudo nano /etc/nginx/conf.d/default.conf

and change line with php section :

1
2
3
4
5
6
7
8
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
}

edit php.ini

1
sudo nano /etc/php/8.2/fpm/php.ini

change option cgi.fix_pathinfo

1
cgi.fix_pathinfo=0

Choose proper web server user for PHP. This is additional settings because we are using official Nginx repo and not the one prepared by Debian. So user is not www-data anymore, but nginx.

1
sudo nano /etc/php/8.2/fpm/pool.d/www.conf

and find parameters listed below and set them as listed:

1
2
3
4
5
user = nginx
group = nginx
listen = /run/php/php8.2-fpm.sock
listen.owner = nginx
listen.group = nginx

Reload php-fpm service:

1
sudo systemctl reload php8.2-fpm

PHP Info

If you would like to check your PHP configuration, create info.php file in your www location:

1
sudo nano /var/www/html/info.php

put this code to this file:

1
2
3
<?php
phpinfo();
?>

and navigate to that file in your browser:

http://example.com/info.php

Don’t forget to delete this file if not needed anymore.

Database creation

Login to your database server:

1
sudo mysql

Create database:

1
CREATE DATABASE database_name;

Create user and password:

1
CREATE USER 'user_name'@'%' IDENTIFIED BY 'password';

Authorize the user to have complete control over the database:

1
GRANT ALL PRIVILEGES ON database_name.* TO 'user_name'@'%';

Forces immediate application of changes in privileges.

1
FLUSH PRIVILEGES;