How to Install LAMP Server (PHP 7.2) on Debian 9 VPS
Please find updated working guide for LAMP stack here : https://dev.slickalpha.blog/2020/05/installing-lamp-stack-on-debian-10-buster.html
This guide includes all commands and codes that can be executed on a Linux terminal (console) to install a LAMP stack on Debian 9 (Stretch), along with PhpMyAdmin and free ssl certificates.
Basic Linux Commands
Print Working Directory
pwd
Change Directory (to root)
cd /
List Current Directory
ls -ahl
-a : all the files
-h : human readable
-l : long list
Change Directory (to var)
cd var
Change Directory (to previous)
cd ..
Text Editior (nano)
Prefix a file path or file name with 'nano' and execute command
To save changes on nano, press ctrl+x and type 'y' (without quotes) and press enter. To discard changes type 'n' instead of 'y'.
Temporarily elevate to root privileges
Prefix a command with 'sudo' and execute command
Prerequisites to install LAMP stack on Debian 9
1. Have deployed a Debian 9 image on your new server and have your root password ready
2. Have pointed your domain (example.com) to your server public ip address
3. Have booted your server and is up and running
Tips & Instructions
1. To copy code from here, use ctrl-c, and to paste it on putty, mouse-right-click once on putty
2. Replace all place holders such as 'example.com', 'example_user', 'nothingtosee' and so on with desired strings.
3. From Debian 9 onwards, you can use 'apt' instead of 'apt-get'.
Steps to install LAMP stack on Debian 9 (Stretch)
Set preference to ipv4 (optional)
nano /etc/gai.conf
uncomment "precedence ::ffff:0:0/96 100" by removing preceding pound
Update & Upgrade Linux
apt update && apt upgrade
When prompted, type y and press enter.
Install sudo (if doesn't exist, and optional)
apt install sudo
Set Hostname (replace xhostname)
hostnamectl set-hostname xhostname
Check if Host File exists
nano /etc/hosts
Update /etc/hosts (replace example.com and xhostname. Add ipv4 and ipv6 with ip found on your vps dashboard)
nano /etc/hosts
127.0.0.1 localhost
[your_ipv_4] xhostname.example.com xhostname
[your_ipv_6] xhostname.example.com xhostname
Check Hostname
hostname
hostname -f
Set Localtime
dpkg-reconfigure tzdata
Install Apache 2 Server
apt update && apt upgrade
apt install apache2 apache2-doc apache2-utils
Turn off KeepAlive
nano /etc/apache2/apache2.conf
Edit 'KeepAlive On' to 'KeepAlive Off'
Edit and enable Prefork module
nano /etc/apache2/mods-available/mpm_prefork.conf
Set MaxConnectionsPerChild to a valid number (eg.100) to prevent memory leaks. Edit other values to fine tune apache.
a2dismod mpm_event
a2enmod mpm_prefork
systemctl restart apache2
Disable default apache virtual host
a2dissite 000-default.conf
Add virtual host configuration and save file (replace example.com)
nano /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerAdmin webmaster@example.com
ServerName example.com
ServerAlias www.example.com
AddType application/x-httpd-php .php
DocumentRoot /var/www/example.com/site/
DirectoryIndex index.php index.html index
ErrorLog /var/www/example.com/logs/error.log
CustomLog /var/www/example.com/logs/access.log combined
</VirtualHost>
Create directories for your public site and logs (replace example.com)
mkdir -p /var/www/example.com/site
mkdir /var/www/example.com/logs
Enable the site and reload apache (replace example.com)
a2ensite example.com.conf
systemctl reload apache2
Install Maria DB Server
Note: Maria DB is same as MySql, just the name.
apt -y install mariadb-server mariadb-client
Secure Maria DB Server (set Y for all and set root pass)
mysql_secure_installation
Adding package sources (For PHP 7.2 only)
Note : PHP 7.2 Packages are obtained from packages.sury.org
apt install apt-transport-https lsb-release ca-certificates
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
apt update
Install PHP 7.2 with FastCGI
Note : PHP 7.2 does not come with Mcrypt, use 'text replacer' at the bottom of this post to change 7.2 to 7.0 for Mcrypt.
apt install php7.2-cli php7.2-cgi php7.2-fpm php7.2-mysql php7.2-json php7.2-curl libapache2-mod-php7.2
apt update
Securing PHP : Edit php.ini, and uncomment and set fix_pathinfo to 0
nano /etc/php/7.2/fpm/php.ini
Set 0 and uncomment (remove preceding semicolon) cgi.fix_pathinfo=0
systemctl restart php7.2-fpm
Create a index file to check php working (replace example.com)
nano /var/www/example.com/site/index.php
Add following lines to test
<?php
echo "Welcome";
?>
And save file and run it on browser http://example.com
To install phpmyadmin
Get the latest pure binary file (.tar.gz) from https://www.phpmyadmin.net/downloads/
wget https://files.phpmyadmin.net/phpMyAdmin/4.7.6/phpMyAdmin-4.7.6-all-languages.tar.gz
tar xvf phpMyAdmin-4.7.6-all-languages.tar.gz
Move and rename the directory (replace 'nothingtosee')
mv phpMyAdmin-4.7.6-all-languages /usr/share/
mv -T /usr/share/phpMyAdmin-4.7.6-all-languages /usr/share/nothingtosee
ls -al /usr/share/
Create Symbolic link to phpmyadmin (replace 'nothingtosee' & 'example.com')
ln -s /usr/share/nothingtosee /var/www/example.com/site
Visit http://example.com/nothingtosee/ to see phpmyadmin page.
To setup phpmyadmin config.inc file, rename the sample file (replace 'nothingtosee')
mv /usr/share/nothingtosee/config.sample.inc.php /usr/share/nothingtosee/config.inc.php
Set blowfish_secret and change _host to '127.0.0.1' in config file and save (replace 'bf_secret')
nano /usr/share/nothingtosee/config.inc.php
$cfg['blowfish_secret'] = 'bf_secret';
$cfg['Servers'][$i]['host'] = '127.0.0.1';
Add password to the phpmyadmin page (replace example_user with username and enter a password for auth)
htpasswd -c -B /etc/apache2/pma_pass example_user
Edit hosts file to reflect addition (replace example.com) and add the following within VirtualHost tag
nano /etc/apache2/sites-available/example.com.conf
<Directory "/var/www/example.com/site/nothingtosee">
AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/pma_pass
Require valid-user
</Directory>
systemctl restart apache2
Visit http://example.com/nothingtosee/ to see auth.
Creating MariaDB database for Limited user
Login in to MariaDB (with root pass)
mariadb -u root -p
Create a database for limited user (replace db_name, db_user, db_pass)
CREATE DATABASE db_name;
CREATE USER 'db_user' IDENTIFIED BY 'db_pass';
GRANT ALL PRIVILEGES ON db_name.* TO 'db_user'@'127.0.0.1' IDENTIFIED BY 'db_pass'
Configure mysql.user table for remote access.
SELECT User, Host, plugin FROM mysql.user;
The database should look like this. If the host or plugin is set different, then update the table to look like this. (replace example_user only)
UPDATE mysql.user SET plugin = 'mysql_native_password' WHERE User='example_user';
DELETE FROM mysql.user WHERE Host = '%';
FLUSH PRIVILEGES;
\q
Restart MariaDB to conclude
service mariadb restart
systemctl restart php7.2-fpm
Create a new group (replace example_group)
addgroup --system example_group
Add Limited User Account (replace example_user and enter password for user)
adduser example_user
Mod limited_user to the group with root directory (replace example.com)
usermod -g example_group -d /var/www/example.com/site -s /sbin/nologin example_user
Restrict and give limited user r(4)/w(2)/x(1) permissions
chown -R root:root /var/www/
chmod -R 755 /var/www/example.com/
chown -R example_user:example_group /var/www/example.com/site
chmod -R 775 /var/www/example.com/site
Edit sshd_config
nano /etc/ssh/sshd_config
Comment out following line in sshd_config (add a preceding pound)
#Subsystem sftp /usr/lib/openssh/sftp-server
Add following lines to sshd_config (replace example.com & example_group)
Subsystem sftp internal-sftp
Match Group example_group
ChrootDirectory /var/www/example.com
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp
Restart ssh to confirm changes
service ssh restart
apt update
systemctl restart apache2
Try authenticating using Filezilla to confirm access
Also try logging into phpmyadmin with the limited user credentials to operate db.
Install UFW for Firewall
apt install ufw
Edit config file and set 'IPV6=yes' if using ipv6
nano /etc/default/ufw
ufw default deny incoming
ufw default allow outgoing
Allow tcp 22 or 2222 for ssh access
ufw allow 22/tcp
ufw allow www
ufw allow ftp
To update disable and enable (enable turn it on, make sure ssh is enabled)
ufw disable
ufw enable
To check status of firewall
ufw status verbose
Install certbot client to obtain ssl from letsencrypt.com
apt install certbot
Add following block within site config for webroot (replace example.com)
nano /etc/apache2/sites-available/example.com.conf
AliasMatch ^/.well-known/acme-challenge/(.*)$ /var/www/example.com/.well-known/acme-challenge/$1
Alias /.well-known/acme-challenge/ /var/www/example.com/.well-known/acme-challenge/
<Directory "/var/www/example.com/.well-known/acme-challenge/">
Options None
AllowOverride None
ForceType text/plain
RedirectMatch 404 "^(?!/\.well-known/acme-challenge/[\w-]{43}$)"
</Directory>
To test a certificate using staging environment before using production environment (optional)
certbot certonly --staging --webroot --agree-tos -d example.com -w /var/www/example.com/
To get a production level certificate using webroot (Limited to 5 attempts/hr)
certbot certonly --webroot --agree-tos -d example.com -w /var/www/example.com/
To get certificates for sub domains (optional)
certbot certonly --webroot --agree-tos -d example.com -d www.example.com -w /var/www/example.com/
Check for four symbolic links in /etc/letsencrypt/live/example.com
· cert.pem: Your domain's certificate
· chain.pem: The Let's Encrypt chain certificate
· fullchain.pem: cert.pem and chain.pem combined
· privkey.pem: Your certificate's private key
ls -l /etc/letsencrypt/live/example.com
Replace port 80 with 443 on host file and add a redirect for port 80 (replace example.com)
nano /etc/apache2/sites-available/example.com.conf
The final site config file should similar to this, with ssl config (replacing example.com & nothingtosee)
<VirtualHost *:80>
ServerAdmin webmaster@example.com
ServerName example.com
DocumentRoot /var/www/example.com/site/
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster@example.com
ServerName example.com
AddType application/x-httpd-php .php
DocumentRoot /var/www/example.com/site/
DirectoryIndex index.php index.html index
ErrorLog /var/www/example.com/logs/error.log
CustomLog /var/www/example.com/logs/access.log combined
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
Header always set Strict-Transport-Security "max-age=15768000"
RequestHeader append "X-Forwarded-Proto" "https"
RequestHeader set "X-Forwarded-Ssl" "on"
<Directory "/var/www/example.com/site/nothingtosee">
AuthType Basic
AuthName "Restricted Content"
AuthUserFile /etc/apache2/pma_pass
Require valid-user
</Directory>
AliasMatch ^/.well-known/acme-challenge/(.*)$ /var/www/example.com/.well-known/acme-challenge/$1
Alias /.well-known/acme-challenge/ /var/www/example.com/.well-known/acme-challenge/
<Directory "/var/www/example.com/.well-known/acme-challenge/">
Options None
AllowOverride None
ForceType text/plain
RedirectMatch 404 "^(?!/\.well-known/acme-challenge/[\w-]{43}$)"
</Directory>
</VirtualHost>
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
sudo a2enmod ssl
a2enmod headers
systemctl restart apache2
To get a rating on the ssl, visit the following site (replace example.com)
https://www.ssllabs.com/ssltest/analyze.html?d=example.com
Add 443/https port to ufw firewall
ufw allow https
Delete http if necessary (http pages will not load)
ufw delete allow www
Check status of ufw
ufw status verbose
Install Cron for automated updates
apt update
apt install cron
Restrict all user access. Allow access for example_user (if necessary)
echo ALL /etc/cron.deny
echo example_user /etc/cron.allow
Add following two lines to crontab for letsencrypt ssl auto renewal
crontab -e
30 1 * * * /usr/bin/certbot renew >> /var/log/le-renew.log
35 1 * * * /bin/systemctl restart apache2
Note: All commands were tested successfully on a VPS running Debian 9. Write us, if you need support or need an installation.
Optional Items
To support .htaccess and rewrites within site, add this to the configuration file, at the bottom.(replace example.com)
nano /etc/apache2/apache2.conf
<Directory /var/www/example.com/site>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
a2enmod rewrite
service apache2 restart
To install Mcrypt (For PHP <=7.0 only)
apt install php7.0-mcrypt php-mbstring php7.0-mbstring php-gettext
phpenmod mcrypt
phpenmod mbstring
systemctl restart php7.0-fpm
service apache2 restart
To Delete Limited User Account
deluser --remove-home username
To Delete any folders (created by mistake)
rm -r -f /path/
To change mysql root pass (use root pass)
mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'password';
Text Replacer Tool (This -> That)
Post a Comment