Install and Configure LEMP Stack in Debian 9

LEMP stack is an acronym which stands for the following packages combined together: Linux kernel, Nginx web server, MariaDB database (or MySQL) and PHP server-side programming language). These pieces of software are widely used on servers on the internet today to deploy dynamic websites or interactive web applications. 

Nginx is a modern and resources efficient web server, actively under development, and the second most used on the internet after Apache HTTP server due to the fact that it uses an asynchronous event-driven approach to handle requests.

This tutorial will guide you on how to install and configure LEMP stack (Nginx with MariaDB and PHP7) on the latest release of Debian 9.


  • Latest release of Debian 9 operating system, which can be obtained from the following link , installed  from scratch on a VPS, virtual machine or directly on a self-dedicated machine.
  • Direct access to server's console or remote SSH connection
  • A network interface configured with a static IP address for the machine
  • A registered public domain name with A and CNAME (www) DNS records configured on nameserver's side. On this guide we’ll use the as an example domain.  The IP address of the server is configured with an IP address belonging to C class private space, NAT-ed in internet via the main router. The domain will visible from internet by port forwarding the Apache 80 and 443 ports from the main router to the IP address of the internal server.

Step 1: Initial Configuration

On the first step, login with root or with a user with root privileges in your system and update Debian 9 components (kernel upgrades, package updates and security patches) by issuing the following commands.

sudo apt  update

sudo apt upgrade

sudo apt dist-upgrade

Next, you make sure you add a descriptive name for your machine hostname by running the below command. Subsequently, you should restart the system in order to apply the new hostname accordingly.

sudo hostnamectl set-hostname

sudo init 6

Next, go ahead and install net-tools wget, curl and bash-completion utilities in order to use them later to easily administer your Debian server.

sudo apt install net-tools sudo wget curl bash-completion

Step 2: Install the Nginx Web Server

Nginx is a modern and resources efficient web server used to display web pages to visitors on the internet. Install Nginx web server from Debian 9 official repositories by running the below command in your server’s console.

sudo apt-get install nginx

 Installation of Nginx web server

As shown in the above image the apt package manager will check additional dependecies for the package and ask you if you agree to continue with the installation process. Answer with yes (y) in order to install Nginx.

Next, run netstat command in order to display network sockets on your system and verify if nginx daemon is listening on port 80/TCP. Alternatively, you might want to issue systemctl command in order to check the status of nginx daemon as illustrated in the below image.

sudo netstat -tlp

sudo netstat –tlpn

sudo systemctl status nginx.service

 Check nginx service

Once the nginx server is up and running in your system, issue ifconfig command in order to display network interfaces information and list the IP addresses of your machine.  Then, open a browser and visit Nginx default web page via HTTP protocol by adding the IP address in your browser. The message “Wellcome to Nginx!” should be displayed on your browser window.


Nginx welcome page

Step 3: Activate Nginx HTTP/2.0 Protocol

By default, the latest releases of Nginx binaries provided by Debian 9 repositories are built with HTTP/2.0 protocol. HTTP/2.0 is incorporated into TSL/SSL protocols and can improve the load speed of web pages via secured transactions.

All modern browsers, such as Chrome or Firefox should support this protocol by default. However, be aware that Microsoft Internet Explorer and Microsoft Edge browsers cannot parse the http2 protocol yet. 

In order to enable the HTTP/2.0 protocol in Nginx on Debian 9, you need to make some changes to nginx default configuration file or create a new configuration file and add the TLS block of code for 443 server. In order to accomplish this, first make a backup of Nginx sites-available default configuration by issuing the below command. Confirm that the backup was successfully by listing the sites-available directory content.

sudo cp /etc/nginx/sites-available/default{,.backup}

ls /etc/nginx/sites-available/

Next, create Nginx TLS configuration file using a text editor and add the following content.

sudo nano /etc/nginx/sites-available/default.ssl

default-ssl file excerpt:

    server {
                listen 443 ssl http2 default_server;
                listen [::]:443 ssl http2 default_server;
       #server_name  www.domain.tld;
                server_name _;
                root /var/www/html;
                access_log /var/log/nginx/access.log;
                error_log /var/log/nginx/error.log;
                #SSL Certificates
                ssl_certificate "/etc/nginx/ssl/cert.pem";
                ssl_certificate_key "/etc/nginx/ssl/privekey.pem";
                ssl_dhparam /etc/nginx/ssl/dhparam.pem;
                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                #ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
                ssl_session_cache shared:SSL:1m;
                ssl_session_timeout 10m;
                ssl_ciphers HIGH:!aNULL:!MD5;
                ssl_prefer_server_ciphers  on;
                add_header Strict-Transport-Security "max-age=31536000;
    #includeSubDomains" always;
                location / {
        index index.php index.html index.htm;
                    try_files $uri $uri/ /index.php?$args $uri/ =404;
                                set $cache_uri $request_uri;
                location ~ /.well-known {
                allow all;
               location ~ \.php$ {
                                include snippets/fastcgi-php.conf;
                #             # With php-fpm (or other unix sockets):
                              fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
                #             # With php-cgi (or other tcp sockets):
               #             fastcgi_pass;
                # deny access to .htaccess files, if Apache's document root
                # concurs with nginx's one
                #location ~ /\.ht {
                #             deny all;

The statement that enables the use of HTTP/2.0 protocol is represented by the word http2 from the below line.

 listen 443 ssl http2 default_server; 

In case your visitor's browsers don't support HTTP2 protocol, remove the http2 word from your server configurations in order to disable the protocol and restart nginx service to apply changes.

In case you have a registered domain or you use virtual hosting based on IP addresses you should add your domain name or IP address after the server_name directive as shown in the below example.


Once you finished editing Nginx default configuration file with the above settings

In the above nginx TSL configuration file we’ve specified the path for TLS certificate and key. Since we don’t actually have the keys installed in your system yet, issue the following command in order to generate the self-signed SSL certificate file and key. While generating the SSL certificate you would be asked a series of questions. Add the two letter code for your country, the state or province, the name of your city, the name of your organization, the unit name of your organization, the common name of your server and a valid email address.  You should pay attention to Common Name setting so that it matches your machine FQDN record from the DNS server or your server IP address that will be used to access the web page. The certificate and key will be stored in a new directory under nginx directory, named ssl as shown in the below screenshot.

sudo mkdir /etc/nginx/ssl

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/privekey.pem -out /etc/nginx/ssl/cert.pem

ls /etc/nginx/ssl/

 Create SSL certificate

Also, generate a new strong Diffie-Hellman cipher, which can be found in the above configuration file on ssl_dhparam statement line, by issuing the below command:

sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

 SSL Cert created

Finally, after you’ve generated the Diffie-Hellman key, activate the TLS configuration file by creating a symbolic link for defult-ssl configuration file from sites-available directory to sites-enabled directory by issuing the following command.

ln -s /etc/nginx/sites-available/default-ssl /etc/nginx/sites-enabled/

Next, test Nginx configuration file for syntax errors and, if everything is ok, restart Nginx daemon in order to apply all changes by running the below commands.

sudo nginx -t

sudo systemctl restart nginx.service

In order to confirm if Nginx web server is binding on SSL port, issue netstat command and check if port 443 is displayed in listening mode.

netstat –tlpn | grep nginx

 The below screenshot illustrated the above steps.

Check service with netstat

Then, navigate to your domain name or your server’s IP address via HTTP protocol from a browser to display nginx default page. Because you’re using self-signed certificates, an error should be displayed in your browser. Confirm the error in order to pass to the nginx default main page.

Self signed SSL certificate warning

In case Nginx doesn’t provide a default index.html page in webroot directory, issue the following command to create the index page.

echo "test page" | tee /var/www/html/index.html

 SSL test page

 In order to confirm the presence of HTTP/2.0 protocol advertised by Nginx, issue the below command. Look for h2 word in protocols advertised by the server. 

 openssl s_client -connect localhost:443 -nextprotoneg ''

 Test SSL certificate with openssl command

You can also visualize the state of the connection and check if http2 protocol is advertised by Nginx from Chrome browser by pressing F12 function key and request the page. In order to show the protocol used by the request, go to Network tab, right click on Type menu and check Protocol filed. HTTP2 protocol should be displayed as h2 in the current protocol column, as illustrated in the below screenshot.

 Test certificate in browser

Step 4: Install PHP7.0

Nginx web server can serve dynamic web content with the help of PHP programming language interpreter via PHP FastCGI process manager to which Nginx passes the requests for processing. FastCGI process manager can be obtained by installing the php-fpm pre-compiled package offered by Debian 9 official repositories.

In order to install php-fpm process manager and PHP7.0 interpreter in the system alongside with the additional packages that will allow PHP to communicate with Nginx web server, issue the below command on your server console:

sudo apt install php7.0 php7.0-fpm php7.0-curl php7.0-gd


Once the PHP7.0 interpreter has been successfully installed in your system, start and check php7.0-fpm daemon by issuing the below command:

sudo systemctl start php7.0-fpm

sudo systemctl status php7.0-fpm

In the above TLS configuration file of Nginx, we’ve already added the block configurations for PHP FastCGI process manager in order to serve dynamic content. The block of code that enables Nginx to use PHP interpreter is shown in the below excerpt, so no steps are needed further to modify Nginx TSL configuration file. The hashtag # sign from the beginning of the lines in the below screenshot are comments. Commented lines from configuration files are ignored by default by Nginx web server.

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;

 Enable PHP in Nginx

In order to test and validate if Nginx can correctly pass php files to PHP processor, create a PHP info.php test configuration file by issuing the below command

sudo su -c 'echo "<?php phpinfo(); ?>" > /var/www/html/info.php'

Then, visit php info page in your web browser by navigating to your server's domain name or public IP address followed by /info.php as shown in the below image.


phpinfo output

You can also check if HTTP/2.0 protocol is advertised by the server by searching for the line $_SERVER[‘SERVER_PROTOCOL’] on PHP Variables.

To install other PHP7.0 modules, run the apt search php7.0 command to find a specific PHP module and install it. If you are planning to install a Content Management System, such as Wordpress, on top of your LEMP stack, issue the following command to install some extra PHP modules.

sudo apt install php7.0-mcrypt php7.0-mbstring

However, the newly installed PHP modules are not enabled by default on your system. In order to activate a new installed PHP module for Nginx, you should restart PHP-FPM service by issuing the below command.

sudo systemctl restart php7.0-fpm.service

Step 5: Install MariaDB Database

Finally, the last piece of the LAMP stack puzzle missing in the database. The MariaDB database LEMP component is used for storing records in tables and columns and dynamically manage the data of a web application. In order to install MariaDB database management system in Debian 9 with the required PHP module to access the database from PHP files, issue the below command in your server’s console. Subsequently, restart PHP-FPM daemon in order to activate the PHP MySQL module needed to access the database.

sudo apt install mariadb-server mariadb-client php7.0-mysql

sudo systemctl restart php7.0-fpm.service

By default, the system root account or users with root privileges can access the database without providing a password. In order to change this behavior, so that MySQL asks for a password each time a system user tries to access the database, log in to MySQL database from command line interface, with root privileges, and execute the following commands in MySQL console:

sudo mysql

MariaDB> use mysql;
MariaDB> update user set plugin='' where User='root';
MariaDB> flush privileges;
MariaDB> exit


On the next step, make sure you secure MariaDB by executing the security script mysql_secure_installation provided by the installation package from Debian stretch repositories. While running the script will ask a series of questions designed to secure MariaDB database, such as: to change MySQL root password, to remove anonymous users, to disable remote root logins and delete the test database. Execute the script by issuing the below command and assure you say yes to all questions asked in order to fully secure MySQL daemon. Use the below script output except as a guide.

sudo mysql_secure_installation




In order to log into MariaDB to secure it, we'll need the current

password for the root user.  If you've just installed MariaDB, and

you haven't set the root password yet, the password will be blank,

so you should just press enter here.


Enter current password for root (enter for none):

OK, successfully used password, moving on...


Setting the root password ensures that nobody can log into the MariaDB

root user without the proper authorisation.


You already have a root password set, so you can safely answer 'n'.


Change the root password? [Y/n] y

New password:

Re-enter new password:

Password updated successfully!

Reloading privilege tables..

 ... Success!



By default, a MariaDB installation has an anonymous user, allowing anyone

to log into MariaDB without having to have a user account created for

them.  This is intended only for testing, and to make the installation

go a bit smoother.  You should remove them before moving into a

production environment.


Remove anonymous users? [Y/n] y

 ... Success!


Normally, root should only be allowed to connect from 'localhost'.  This

ensures that someone cannot guess at the root password from the network.


Disallow root login remotely? [Y/n] y

 ... Success!


By default, MariaDB comes with a database named 'test' that anyone can

access.  This is also intended only for testing, and should be removed

before moving into a production environment.


Remove test database and access to it? [Y/n] y

 - Dropping test database...

 ... Success!

 - Removing privileges on test database...

 ... Success!


Reloading the privilege tables will ensure that all changes made so far

will take effect immediately.


Reload privilege tables now? [Y/n] y

 ... Success!


Cleaning up...


All done!  If you've completed all of the above steps, your MariaDB

installation should now be secure.


Thanks for using MariaDB!


Finally, in order to test MariaDB functionality, login to the database from console and execute the following command. A list of the default databases should be displayed in MariaDB console. Leave MariaDB console with exit statement.

mysql -u root –p

MariaDB [(none)]> show databases;
| Database           |
| information_schema |
| mysql              |
| performance_schema |
3 rows in set (0.00 sec)
MariaDB [(none)]> exit

 MariaDB show databases

That’ all! Nginx web server, MariaDB database, and PHP programming language are installed on your Debian 9 machine.  You can now start building dynamic web sites or web application for your visitors.

Share this page:

Suggested articles

0 Comment(s)

Add comment