How to Install LAMP Server (PHP 7.2) on Debian 9 VPS





Before starting with, make sure you have a server instance ready to test installation. Try VULTR for cheap and reliable VPS servers.

 

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

4. This guide uses putty for terminal. You can also use Vultr console instead, found on options menu in VULTR dashboard.

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

Adding a limited access SFTP user to access site files

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>

Getting a certificate using webroot and certbot. (Enter an email for updates)

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)

Enable apache2 ssl and headers module and restart apache

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)
Copyright Slickalpha.com | All Rights Reserved. Powered by Blogger.