How To Install Linux, Apache, MySQL, PHP (LAMP) Stack on Debian 9 Stretch

Posted on in Categories , , , , , last updated September 24, 2017

I am a new user of Debian 9 operating system. Can you tell me how to setup and install LAMP stack on a Debian 9 (Stretch)?

LAMP is an acronym for four open source software frequently used to develop the web applications (such as forums, blogs, and business sites):

  1. Linux operating system
  2. Apache web server
  3. MySQL/MariaDB relational database management system (RDBMS)
  4. PHP server-side programming language

This tutorial shows you how to install LAMP (Apache version 2, PHP version 7, MariaDB version 10.2) stack on a Debian 9 Linux server along with firewall settings to open tcp port 80, 22, and 443.

Step 1: Apply patches if any

Type the following apt-get command/apt command to update the system:
$ sudo apt update
Sample outputs:

Hit:1 http://security.debian.org stretch/updates InRelease  
Hit:2 http://cdn-fastly.deb.debian.org/debian stretch InRelease
Reading package lists... Done
Building dependency tree       
Reading state information... Done
38 packages can be upgraded. Run 'apt list --upgradable' to see them.

To patch it with the latest updates, run:
$ sudo apt-get upgrade
Sample outputs:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  apt bash debconf debian-archive-keyring debianutils dpkg file gcc-6-base init init-system-helpers libapt-pkg5.0 libc-bin libc-l10n libc6 libcryptsetup4 libdns-export162
  libelf1 libgcc1 libgcrypt20 libisc-export160 libmagic-mgc libmagic1 libpam-modules libpam-modules-bin libpam-runtime libpam0g libssl1.0.2 libssl1.1 libstdc++6
  libsystemd0 libudev1 locales login multiarch-support passwd perl-base systemd systemd-sysv
38 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 26.3 MB of archives.
After this operation, 82.9 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 debianutils amd64 4.8.1.1 [100 kB]
Get:2 http://cdn-fastly.deb.debian.org/debian stretch/main amd64 bash amd64 4.4-5 [1427 kB]
....
..
...
Setting up libmagic1:amd64 (1:5.30-1) ...
Setting up libssl1.0.2:amd64 (1.0.2l-2) ...
Processing triggers for libc-bin (2.24-11) ...
Setting up libssl1.1:amd64 (1.1.0f-3) ...
Setting up libc-l10n (2.24-11) ...
Setting up locales (2.24-11) ...
Generating locales (this might take a while)...
  en_US.UTF-8... done
Generation complete.
Setting up init (1.48) ...
Setting up libdns-export162 (1:9.10.3.dfsg.P4-12.3) ...
Setting up file (1:5.30-1) ...
Processing triggers for libc-bin (2.24-11) ..

Step 2: Install Apache http server

Type the following command:
$ sudo apt install apache2
Sample outputs:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0 ssl-cert
Suggested packages:
  www-browser apache2-doc apache2-suexec-pristine | apache2-suexec-custom openssl-blacklist
The following NEW packages will be installed:
  apache2 apache2-bin apache2-data apache2-utils libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap liblua5.2-0 ssl-cert
0 upgraded, 10 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/2143 kB of archives.
After this operation, 7137 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
ebconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package mime-support.
(Reading database ... 13992 files and directories currently installed.)
Preparing to unpack .../00-mime-support_3.60_all.deb ...
Unpacking mime-support (3.60) ...
Selecting previously unselected package libapr1:amd64.
....
..
...
Enabling module filter.
Enabling module deflate.
Enabling module status.
Enabling module reqtimeout.
Enabling conf charset.
Enabling conf localized-error-pages.
Enabling conf other-vhosts-access-log.
Enabling conf security.
Enabling conf serve-cgi-bin.
Enabling site 000-default.
Created symlink /etc/systemd/system/multi-user.target.wants/apache2.service ? /lib/systemd/system/apache2.service.
Created symlink /etc/systemd/system/multi-user.target.wants/apache-htcacheclean.service ? /lib/systemd/system/apache-htcacheclean.service.
Processing triggers for libc-bin (2.24-11) ...
Processing triggers for systemd (232-25) ...

You can view default page by typing the IP address of your server. To find the IP address of your server use the ip command/ifconfig command as follows:
$ ifconfig eth0
$ ip a show eth0
$ ip a show eth0 | grep -w inet

Sample outputs:

inet 10.114.13.8/24 brd 10.114.13.255 scope global eth0

Fire a web browser and type the following url:
http://10.114.13.8
Sample outputs:

Fig.01: Default Debian 9 Apache 2 page
Fig.01: Default Debian 9 Apache 2 page

The Apache HTTP server successfully installed on your server. You can change the default page by editing the index.html file located in /var/www/html/ directory:
$ sudo vi /var/www/html/index.html

How do I stop/start/restart/reload Apache HTTP server?

The syntax is as follows:
$ sudo systemctl {start|stop|restart|reload|status|graceful-stop|force-reload} apache2
To stop Apache 2 server, run:
$ sudo systemctl stop apache2
To start Apache 2 server, run:
$ sudo systemctl start apache2
To restart Apache 2 server, run:
$ sudo systemctl restart apache2
To reload Apache 2 server, run:
$ sudo systemctl reload apache2
To see status of Apache 2 server, run:
$ sudo systemctl status apache2

Fig.02: Controlling Apache 2 server with systemctl command
Fig.02: Controlling Apache 2 server with systemctl command

How do I change configuration of Apache HTTP server?

You need to edit files located in /etc/apache2/ directory:
$ cd /etc/apache2/
$ ls -l

Sample outputs:
total 32

-rw-r--r-- 1 root root  7224 Jan 25 22:59 apache2.conf
drwxr-xr-x 2 root root     7 Jun 13 18:46 conf-available
drwxr-xr-x 2 root root     7 Jun 13 18:46 conf-enabled
-rw-r--r-- 1 root root  1782 Jan 25 21:16 envvars
-rw-r--r-- 1 root root 31063 Jan 25 21:16 magic
drwxr-xr-x 2 root root   138 Jun 13 18:46 mods-available
drwxr-xr-x 2 root root    31 Jun 13 18:46 mods-enabled
-rw-r--r-- 1 root root   320 Jan 25 21:16 ports.conf
drwxr-xr-x 2 root root     4 Jun 13 18:46 sites-available
drwxr-xr-x 2 root root     3 Jun 13 18:46 sites-enabled

You need to edit or add a new config file in /etc/apache2/conf-available/ directory. Here is a default config file:
$ cat /etc/apache2/sites-enabled/000-default.conf
Sample outputs:

<VirtualHost *:80>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com
 
	ServerAdmin [email protected]
	DocumentRoot /var/www/html
 
	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
	# error, crit, alert, emerg.
	# It is also possible to configure the loglevel for particular
	# modules, e.g.
	#LogLevel info ssl:warn
 
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
 
	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf
</VirtualHost>
 
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

See Apache Name Based VirtualHost Example for more info on how to configure virtual hosting on Debian 9.

Step 3: Install MariaDB server

MariaDB is RDBMS and drop in replacement for original MySQL server. It is one of the most popular database servers in the world. It’s made by the original developers of MySQL and guaranteed to stay open source. To install MariaDB server, run:
$ sudo apt install default-mysql-server
OR
$ sudo apt install mariadb-server
Sample outputs:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  galera-3 gawk libaio1 libarchive13 libcgi-fast-perl libcgi-pm-perl libdbd-mysql-perl libdbi-perl libencode-locale-perl libfcgi-perl libhtml-parser-perl
  libhtml-tagset-perl libhtml-template-perl libhttp-date-perl libhttp-message-perl libio-html-perl libjemalloc1 liblwp-mediatypes-perl liblzo2-2 libmariadbclient18
  libmpfr4 libreadline5 libreadline7 libsigsegv2 libterm-readkey-perl libtimedate-perl liburi-perl mariadb-client-10.1 mariadb-client-core-10.1 mariadb-common
  mariadb-server-10.1 mariadb-server-core-10.1 mysql-common psmisc readline-common socat
Suggested packages:
  gawk-doc lrzip libclone-perl libmldbm-perl libnet-daemon-perl libsql-statement-perl libdata-dump-perl libipc-sharedcache-perl libwww-perl mailx mariadb-test
  netcat-openbsd tinyca readline-doc
The following NEW packages will be installed:
  default-mysql-server galera-3 gawk libaio1 libarchive13 libcgi-fast-perl libcgi-pm-perl libdbd-mysql-perl libdbi-perl libencode-locale-perl libfcgi-perl
  libhtml-parser-perl libhtml-tagset-perl libhtml-template-perl libhttp-date-perl libhttp-message-perl libio-html-perl libjemalloc1 liblwp-mediatypes-perl liblzo2-2
  libmariadbclient18 libmpfr4 libreadline5 libreadline7 libsigsegv2 libterm-readkey-perl libtimedate-perl liburi-perl mariadb-client-10.1 mariadb-client-core-10.1
  mariadb-common mariadb-server-10.1 mariadb-server-core-10.1 mysql-common psmisc readline-common socat
0 upgraded, 37 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/27.1 MB of archives.
After this operation, 195 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libmpfr4:amd64.
(Reading database ... 14762 files and directories currently installed.)
Preparing to unpack .../libmpfr4_3.1.5-1_amd64.deb ...
....
..
...
Setting up libdbd-mysql-perl (4.041-2) ...
Setting up mariadb-client-10.1 (10.1.23-9+deb9u1) ...
Setting up mariadb-server-10.1 (10.1.23-9+deb9u1) ...
Created symlink /etc/systemd/system/mysql.service ? /lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/mysqld.service ? /lib/systemd/system/mariadb.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mariadb.service ? /lib/systemd/system/mariadb.service.
Setting up default-mysql-server (1.0.2) ...
Processing triggers for libc-bin (2.24-11) ...
Processing triggers for systemd (232-25) ...

How do I secure MariaDB mysql server?

Type the following command:
$ sudo mysql_secure_installation
Sample session:

Fig.03: Keeping your MariaDB database server safe
Fig.03: Keeping your MariaDB database server safe

Please note that MariaDB/mysql root account and system root account are two different accounts. This is not the root account used for your server management. So make sure you set different passwords.

How do I test my MariaDB installation?

Type the following command:
$ mysql -u root -p
You will greeted with MariaDB mysql prompt. You can type sql commands to see databases, version and much more:
MariaDB [(none)]> show databases;
MariaDB [(none)]> exit

Sample outputs:

Fig.04: Testing MariaDB/MySQL server installation
Fig.04: Testing MariaDB/MySQL server installation

See the following tutorials for additional tasks such as adding a new database, users and SSL config:

  1. Mysql User Creation: Setting Up a New MySQL User Account
  2. Create a MySQL Database, Tables and Insert Data
  3. How to setup MariaDB SSL and secure connections from clients

Step 4: Install PHP version 7

PHP version 7 is at least 30-50% faster as compare to PHP 5.6. So let us install PHP version 7 along with php modules for on a Debian 9 server:
$ sudo apt install php7.0 libapache2-mod-php7.0 php7.0-mysql php7.0-gd php7.0-opcache
Sample outputs:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  fontconfig-config fonts-dejavu-core libfontconfig1 libfreetype6 libgd3 libjbig0 libjpeg62-turbo libpng16-16 libtiff5 libwebp6 libx11-6 libx11-data libxau6 libxcb1
  libxdmcp6 libxpm4 php-common php7.0-cli php7.0-common php7.0-json php7.0-readline
Suggested packages:
  php-pear libgd-tools
The following NEW packages will be installed:
  fontconfig-config fonts-dejavu-core libapache2-mod-php7.0 libfontconfig1 libfreetype6 libgd3 libjbig0 libjpeg62-turbo libpng16-16 libtiff5 libwebp6 libx11-6 libx11-data
  libxau6 libxcb1 libxdmcp6 libxpm4 php-common php7.0 php7.0-cli php7.0-common php7.0-gd php7.0-json php7.0-mysql php7.0-opcache php7.0-readline
0 upgraded, 26 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/8,129 kB of archives.
After this operation, 25.9 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libxau6:amd64.
(Reading database ... 15880 files and directories currently installed.)
Preparing to unpack .../00-libxau6_1%3a1.0.8-1_amd64.deb ...
....
..
..
Setting up libx11-6:amd64 (2:1.6.4-3) ...
Setting up php7.0-cli (7.0.19-1) ...
update-alternatives: using /usr/bin/php7.0 to provide /usr/bin/php (php) in auto mode
update-alternatives: using /usr/bin/phar7.0 to provide /usr/bin/phar (phar) in auto mode
update-alternatives: using /usr/bin/phar.phar7.0 to provide /usr/bin/phar.phar (phar.phar) in auto mode
 
Creating config file /etc/php/7.0/cli/php.ini with new version
Setting up libxpm4:amd64 (1:3.5.12-1) ...
Setting up libapache2-mod-php7.0 (7.0.19-1) ...
 
Creating config file /etc/php/7.0/apache2/php.ini with new version
Module mpm_event disabled.
Enabling module mpm_prefork.
apache2_switch_mpm Switch to prefork
apache2_invoke: Enable module php7.0
Setting up libgd3:amd64 (2.2.4-2) ...
Setting up php7.0 (7.0.19-1) ...
Setting up php7.0-gd (7.0.19-1) ...
 
Creating config file /etc/php/7.0/mods-available/gd.ini with new version
Processing triggers for libc-bin (2.24-11) ...
Processing triggers for libapache2-mod-php7.0 (7.0.19-1) ...

This will install:

  1. PHP version 7 for Apache 2
  2. PHP 7 mysql connectivity module
  3. PHP 7 OpCache module to speed up scripts
  4. PHP 7 GD module for graphics

You can search and install additional PHP modules using the following syntax:
## [search php7 modules] ##
$ apt-cache search php7 | grep module
$ apt search php7 | grep mysql
$ apt-cache search php7 | egrep 'mysql|gd|zip'
$ apt-cache search php7 | more
$ apt search php7 | more
## [search php7 modules] ##
$ sudo apt install {module-name-here}

Finally, restart Apache 2 HTTP server, run:
$ sudo systemctl restart apache2
To test PHP installation, create a script called test.php in /var/www/html/ directory:
$ sudo vi /var/www/html/test.php
Append the following PHP code in it:

<?php phpinfo(); ?>

Fire a web-browser and type the following url:
http://10.114.13.8/test.php
Sample outputs:

Fig.05: Testing PHP 7 with Apache 2
Fig.05: Testing PHP 7 with Apache 2

PHP now installed and running on your server. It is time to secure PHP, see:

  1. Linux: 25 PHP Security Best Practices For Sys Admins

At this stage you have a full fledged LAMP server running a Debian 9.

Step 5: Configure firewall to open port 80 and 443

Type the following command to install ufw firewall frontend:
$ sudo apt install ufw
Sample outputs:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  ufw
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 164 kB of archives.
After this operation, 848 kB of additional disk space will be used.
Get:1 http://mirrors.kernel.org/debian stretch/main amd64 ufw all 0.35-4 [164 kB]
Fetched 164 kB in 0s (180 kB/s)
Preconfiguring packages ...
Selecting previously unselected package ufw.
(Reading database ... 43888 files and directories currently installed.)
Preparing to unpack .../archives/ufw_0.35-4_all.deb ...
Unpacking ufw (0.35-4) ...
Setting up ufw (0.35-4) ...
 
Creating config file /etc/ufw/before.rules with new version
 
Creating config file /etc/ufw/before6.rules with new version
 
Creating config file /etc/ufw/after.rules with new version
 
Creating config file /etc/ufw/after6.rules with new version
Created symlink /etc/systemd/system/multi-user.target.wants/ufw.service ? /lib/systemd/system/ufw.service.
Processing triggers for systemd (232-25) ...
Processing triggers for man-db (2.7.6.1-2) ...
Processing triggers for rsyslog (8.24.0-1) ...

You must allow access to SSH port 22:
$ sudo ufw allow 22
Rules updated
Rules updated (v6)

Open port 80 and 443
$ sudo ufw allow 80
$ sudo ufw allow 443

Now you have default policy and ssh port including 80/443 allowed. It is safe to start enable the firewall, enter:
$ sudo ufw enable
Sample outputs:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

To see firewall rules, run:
$ sudo ufw status verbose
Sample outputs:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

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

And there you have it, LAMP installed and running sucessfully on a Debian 9 system. Take a look at other tutorials for more info:

Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on Twitter, Facebook, Google+.

3 comment

  1. Word of warning: ppl coding in PHP are lazy, so support for PHP7 is seriously lacking.

Comments are closed.