Linux – Apache – MySQL – PHP – How to Install LAMP Stack on Debian
LAMP is an open-source-based combination of software that is usually installed together to allow a server to hosting dynamic websites and web apps. LAMP is the acronym for Linux Apache MySQL PHP, which stands for Linux with the Apache web server, together with the MySQL database and PHP for dynamic CMS sites.
In this tutorial, the LAMP stack is installed and configured on a Debian 10 (buster) complete with Apache/2.4, MariaDB 10, PHP 7.4 and vsftpd as well as Fail2ban and all necessary packages. The estimated time required for the installation is around 10 minutes, at the end of which a web server is ready to use for content management systems. Newly created users for FTP access are automatically chrooted to their own DocumentRoot.
Install LAMP Stack on Debian
We are rooted on a Debian 10 Linux, as always update is done before more packages are installed.
First, required packages are provided as a prerequisite for further installation.
apt install ca-certificates apt-transport-https lsb-release gnupg curl vim unzip -y
The Debian repository does not contain the latest PHP versions, so we use the Sury repository.
wget -q https://packages.sury.org/php/apt.gpg -O- | apt-key add - echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list
Update the package index again.
Now install the Apache 2 web server on Debian 10.
apt install apache2 -y
Install the tools and libraries required by most CMS right away.
apt install php7.4 php7.4-cli php7.4-common php7.4-curl php7.4-gd php7.4-intl php7.4-json php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-readline php7.4-xml php7.4-xsl php7.4-zip php7.4-bz2 libapache2-mod-php7.4 -y
Next, the MariaDB server is installed.
apt install mariadb-server mariadb-client -y
Now let’s run the script to complete the configuration of the MariaDB server.
When you first ask for the current password, you do not have to enter anything, but simply press the Enter key. Confirm the next question regarding changing the root password with Enter. Now a password is assigned for the root user of the MariaDB server (not Linux root). No characters appear as you type, which is normal. Confirm all of the following questions (deletion of the anonymous user, banning the external root login for security reasons, removing the test database and updating the rights) also with Enter. After that, the MariaDB server is fully installed and configured.
How to Install phpMyAdmin
Now we use the command
cd /usr/share to change the directory path where phpMyAdmin we would install.
To download phpMyAdmin, let’s now run wget.
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.zip -O phpmyadmin.zip
Unzip the archive you just downloaded as follows.
After unpacking, remove the downloaded archive.
Then the name of the unzipped directory must be renamed to phpmyadmin, with the following command.
mv phpMyAdmin-*-all-languages phpmyadmin
Grant the required rights to the phpMyAdmin directory.
chmod -R 0755 phpmyadmin
At last rename the phpMyAdmin sample.inc.php file.
mv /usr/share/phpmyadmin/config.sample.inc.php /usr/share/phpmyadmin/config.inc.php
Now let’s create an Apache2 configuration file for phpMyAdmin, with copy & paste of the following lines.
cat <<EOF> /etc/apache2/conf-available/phpmyadmin.conf # phpMyAdmin Apache configuration Alias /phpmyadmin /usr/share/phpmyadmin <Directory /usr/share/phpmyadmin> Options SymLinksIfOwnerMatch DirectoryIndex index.php </Directory> # Disallow web access to directories that don't need it <Directory /usr/share/phpmyadmin/templates> Require all denied </Directory> <Directory /usr/share/phpmyadmin/libraries> Require all denied </Directory> <Directory /usr/share/phpmyadmin/setup/lib> Require all denied </Directory> EOF
In the Bash Terminal Copy Paste every line in the codebox.
Enable the Apache2 configuration file you just added.
And perform the reload of the Apache2 web server.
systemctl reload apache2
Create the temporary directory that requires phpMyAdmin.
And now assign the web server user the required owner rights for this temporary directory.
chown -R www-data:www-data /usr/share/phpmyadmin/tmp/
For security reasons, password authentication to the MariaDB server is no longer recommended to log in directly as a root user (i.e. via phpMyAdmin).
Create an additional user with all rights, to do this, we log on to the MariaDB server using the MySQL-Client.
mysql -u root
if everything went well, you are now in the MySQL (MariaDB) prompt.
MariaDB [(none)] >
And then hit the following SQL commands to create the MariaDB user and grant the rights.
CREATE USER 'username'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' WITH GRANT OPTION; FLUSH PRIVILEGES;
Replace “username” and “password“with the desired username and password. Finally type exit to leave the MariaDB console.
MariaDB [(none)] > exit
Now you can log in to the MariaDB server with the newly created user (i.e. also via phpMyAdmin).
Enough – your Apache2 web server incl. PHP 7.4, MariaDB server and phpMyAdmin is now ready to use. The phpMyAdmin WebUI can be reached by add /phpmyadmin to the IP address or FQDN in the browser.
Note. you’ll see the following error message at the bottom of the phpmyadmin page when you first log in to /phpmyadmin.
The configuration file now needs a secret passphrase (blowfish_secret).
You need to add a blowfish password to the phpMyAdmin’s config file. Edit config.inc.php and insert a random blowfish passphrase in the line
$cfg['blowfish_secret']here as an example:
vi /usr/share/phpmyadmin/config.inc.php $cfg['blowfish_secret'] = 'ttTo4Zhy6zEOdUatH6vcOQFbXpnnM/WmOZpO1bM9BH2R7i4WZJVpdBntcsvSDVlM'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
Note. if you use vim for editing, you will notice that after entering the insert mode and paste text by press the right mouse key the blockwise Visual mode is turned on — (insert) VISUAL — that behaves undesirably, but this can be quickly solved by disabling the mouse control for vim, let’s do that right away and run
echo "set mouse-=a" > ~/.vimrc
Hint. generating a passphrase is easy as the following command shows.
openssl rand -base64 48 ttTo4Zhy6zEOdUatH6vcOQFbXpnnM/WmOZpO1bM9BH2R7i4WZJVpdBntcsvSDVlM # or another 48 characters long date +%s | sha256sum | base64 | head -c 48 ; echo MjhhMGUwMjYyYjljNWI2MjFiMGZmNmQ5MjdiYjY2MGE2YWNl
Securing and hardening Debian web server
First, the kernel firewall is configured for the web server, only the required services should be allowed incoming. With Debian, the ufw (Uncomplicated Firewall) is enabled by default after installation. The ports required for the web server are opened as follows.
ufw reset ufw allow "WWW Full" ufw allow 20/tcp ufw allow 21/tcp ufw allow 22/tcp ufw allow 40000:50000/tcp ufw default allow outgoing ufw default deny incoming ufw enable
With the following commands the firewall rules can be queried to check the configuration.
ufw status verbose iptables -vnL iptables -S
Use firewalld instead of ufw
If the firewalld package is required for Debian, it can be deactivated with
ufw disable and firewalld can be installed.
apt instll firewalld -y
With Debian, the links for firewalld must be changed.
update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
After installing firewalld, the rules can be defined.
firewall-cmd --zone=public --change-interface=ens192 firewall-cmd --zone=public --permanent --add-service=ssh firewall-cmd --zone=public --permanent --add-service=http firewall-cmd --zone=public --permanent --add-service=https firewall-cmd --zone=public --permanent --add-port=20/tcp firewall-cmd --zone=public --permanent --add-port=40000-50000/tcp firewall-cmd --reload
Note: instead of
interface=ens192, use the interafce name determined with
ip link or
To check the executed policy using the firewalld-cmd list command.
firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: ens192 sources: services: dhcpv6-client ftp http https ssh ports: 40000-50000/tcp 20/tcp protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
To display the current policy use the following commands.
firewall-cmd --list-all firewall-cmd --get-active-zones iptables -vnL
Note: after each change, reload the firewall for the changes to take effect.
How to install FTP server with vsftpd
vsftpd is an FTP server for the old File Transfer Protocol. As an acronym, its name stands for Very Secure File Transfer Protocol Daemon. Whether OpenSSH with sftp is standard on every Linux and FreeBSD, but unfortunately FTP is still widely used.
The vsftpd daemon is installed as follows.
apt install vsftpd -y
Edit the vsftpd configuration file for changes.
We disable anonymous login and allow local users to write.
anonymous_enable=NO local_enable=YES write_enable=YES
Settings for logging and port ranges.
use_localtime=YES xferlog_enable=YES log_ftp_protocol=YES connect_from_port_20=YES xferlog_file=/var/log/vsftpd.log xferlog_std_format=NO pasv_min_port=40000 pasv_max_port=50000
chroot stands for change root and is a function for Unixoid systems to change the root directory. chroot only affects the current process and its child processes, it is a simple jail mechanism in which the FTP utility prevents users from accessing files outside its directory. chroot also provides an easy way to sandbox untrusted data. The chroot settings for VSFTPD users can be found in the file
vsftpd.conf at line
chroot_local_user and change there to
YES, so also with
All users are assigned chroot, except for some that are exempt, for this the file
/etc/vsftpd.chroot_list is created, which contains users who are excluded from chroot.
To deny login altogether for certain users, we add the following lines to the
userlist_deny=YES userlist_enable=YES userlist_file=/etc/vsftpd.userlist
vsftpd.userlist file and add users to be denied. The service accounts should be rejected, as they are often used for attacks. Add one user per row, example:
Root am Daemon sys Sync one backup Admin sshd Lp Sync proxy stratagem Irc Shutdown stop email news Uucp operator games nobody postfix www-data Ftp mysql
Start the vsftpd daemon.
systemctl start vsftpd
Protect the services using Fail2ban
fail2ban is written in Python aims to protect server services against DoS attacks. It checks log files according to predefined patterns and temporarily blocks the corresponding IP addresses in the event of repeated failed access.
fail2ban is installed and configured on Debian as follows.
apt install fail2ban -y
The configuration of fail2ban for a web server with jail filter for watch access to the SSH and FTP service to bann brute-force attacks.
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
After the configuration file jail.conf has been copied, the file jail.local can be loaded into the editor, all settings here override the value in jail.conf.
Settings can be adjusted here and filters for services can be activated or deactivated. The DEFAULT allows a global definition of the options. The options can then be overridden in any jail.
[DEFAULT] bantime = 43200 findtime = 600 maxretry = 5
The options have the following function:
bantimedefines the duration of the blocking, here 12 hours (specified in seconds).
findtimedefines the duration in which failed attempts can take place, here 10 minutes.
maxretryindicates the number of attempts.
By default, fail2ban is only activated with the SSH filter, further filters are activated with
enabled = true.
[sshd] enabled = true # To use more aggressive sshd modes set filter parameter "mode" in jail.local: # normal (default), ddos, extra or aggressive (combines all). # See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details. #mode = normal port = ssh logpath = %(sshd_log)s backend = %(sshd_backend)s [vsftpd] enabled = true # or overwrite it in jails.local to be # logpath = %(syslog_authpriv)s # if you want to rely on PAM failed login attempts # vsftpd's failregex should match both of those formats port = ftp,ftp-data,ftps,ftps-data logpath = %(vsftpd_log)s
Fail2ban Jail Filter query status, and verbose output for SSH.
fail2ban-client status fail2ban-client -vvv status sshd
Note. Since fail2ban 0.10 (IPv6 support) fail2ban executes
actionstart IP-family related on demand by first ban per jail, so
iptables-multiport would create the chain
f2b-sshd only if first IP gets banned in sshd jail.
other useful tools for the web server
apt install open-vm-tools -y apt install dnsutils -y apt install net-tools -y
Add Apache virtual host for new domain
Here a simple script to create a new Apache VirtualHost along with a new document root and it’s own user who can upload files to build the website.
#!/bin/bash if [ $# -lt 2 ]; then echo "Missinng argument!" echo "use: addvhost [example.com] [username]" exit 1 fi # make directory for new docroot mkdir -p /var/www/$1 /var/www/$1/html # add user for new docroot useradd -s /sbin/nologin -d /var/www/$1/html $2 # put index.html into docroot echo -e "<html> <head> <title>Welcome to $1</title> </head> <body> <h1>Howdy! Apache2 virtual host $1 is working!</h1> </body> </html>" > /var/www/$1/html/index.html # assign owner and grant rights chown -R $2:$2 /var/www/$1 chmod -R 755 /var/www # create new apache virtual host config cat <<EOF> /etc/apache2/sites-available/$1.conf <VirtualHost *:80> ServerAdmin webmaster@$1 ServerName $1 ServerAlias www.$1 DocumentRoot /var/www/$1/html ErrorLog /var/log/apache2/error.log CustomLog /var/log/apache2/access.log combined </VirtualHost> EOF # enable the new apache virtual host a2ensite $1 systemctl restart apache2
Save the lines into a script file called
addvhost and run it.
chmod 755 addvhost ./addvhost example.com username
Use the first argument for the domain name and the second for the user name to be created.
Note. do not forget give a secret
After running the script you’ll find a new docroot under /var/www as well as the associated apache virtual host configuration under /etc/apache2/sites-available this is already ebabled.
For HTTPS websites, Certbot can be integrated for Let’s Encrypt SSL certificates, the how to find in this Article.
It is therefore possible to build a complete web server with all the necessary services in a short time without using graphical user interfaces or other tools for setup and administration.