Header Ads

Installing Apache, PHP 7.3 and MariaDB (LAMP) on Debian 10

LAMP stack guide for installing PHP 7.4 alongside PhpMyAdmin and Let's Encypt SSL certificates.

lamp-stack-debian-10


i. Prerequisites

1. Have deployed a Debian 10 image on your new server and have your root password ready. If not perform a full upgrade from Debian 9 or 8.

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 linux terminal to enter commands (or putty for windows).


A. Useful 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 ..`

Elevate to root privileges for whole session

`sudo -i`

To install sudo

`apt install sudo`

B. Instructions
  • 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'.
  • To temporarily elevate to root privileges
  • Prefix a command with 'sudo' and execute command
  • Replace all placeholders such as 'example.com', 'example_user', 'nothingtosee' and so on with desired strings using string replacer tool

ii. String Replacer Tool



I. Upgrading Debian

If not using Debian 10 or if not sure, check the version by entering following commands

`lsb_release -a`

`uname -mrs`

Update and upgrade existing package

`apt update && apt upgrade && apt full-upgrade && apt --purge autoremove`

Backup and change version to 'buster' on sources file
(replace stretch with jessie for Debian 8)

`cp -v /etc/apt/sources.list /etc/apt/sources.list.bak`
`cp -rv /etc/apt/sources.list.d/ /etc/apt/sources.list.d.bak/`
`sed -i 's/stretch/buster/g' /etc/apt/sources.list`
`sed -i 's/stretch/buster/g' /etc/apt/sources.list.d/*`

Check if the packages are changed to buster

`cat /etc/apt/sources.list`

For locales related warnings you can explicitly set the locales by running the commands. This may happen when using a Linux terminal ssh.

`export LANGUAGE=en_US.UTF-8`
`export LC_ALL=en_US.UTF-8`
`export LANG=en_US.UTF-8`
`export LC_CTYPE=en_US.UTF-8`

Or use dpkg to configure locales

`locale-gen en_US en_US.UTF-8`
`dpkg-reconfigure locales`

Update and upgrade the packages and reboot to apply upgrade
(Enter 'Y' for every choice question except for 'Keeping local version...' which is N or O)

`apt update && apt upgrade && apt full-upgrade && apt --purge autoremove`


II. Configuring Network

To set preference to ipv4 (optional)

`nano /etc/gai.conf`

un-comment "precedence ::ffff:0:0/96 100" by removing preceding pound

When prompted, type y and press enter.

To disable ipv6 completely add following lines to sysctl.conf
(optional)

`nano /etc/sysctl.conf`

`net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1`

And execute

`sysctl -p`

Or alternatively edit grub and append "ipv6.disable=1", update and reboot

`nano /etc/default/grub`

GRUB_CMDLINE_LINUX_DEFAULT=".. .. ipv6.disable=1"
GRUB_CMDLINE_LINUX=".. .. ipv6.disable=1"

And execute update and reboot

`update-grub`

Installing Iptables for network security

`apt --reinstall install iptables`

Flush existing (iptables for ipv4 and ip6tables for ipv6)

`iptables -F`

`ip6tables -F`

Note: After adding the following rules do not use the above command to flush instead use the following command.

`iptables-save | awk '/^[*]/ { print $1 } /^:[A-Z]+ [^-]/ { print $1 " ACCEPT" ; } /COMMIT/ { print $0; }' | iptables-restore`

`ip6tables-save | awk '/^[*]/ { print $1 } /^:[A-Z]+ [^-]/ { print $1 " ACCEPT" ; } /COMMIT/ { print $0; }' | ip6tables-restore`

To show status

`iptables -S`

`ip6tables -S`

or

`iptables --list`

or

`iptables -L -n`

Create iptables script as shell script (replace x.x.x.x with your ipv4 address)

Note : the following rules do not guarantee anything, but provides basic protection from attacks.

Ports : remove port numbers or lines associated, to disable those ports
  • 22 - SSH
  • 80 - HTTP
  • 443 - HTTPS
  • 25, 465 - SMTP
  • 587 - SMTPS
  • 110 - POP3
  • 995 - POP3S
  • 143 - IMAP
  • 993 - IMAPS

`nano iptables.sh`

Rules for ipv4 (when enabled)

`::bash::iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

iptables -4 -A INPUT -s 127.0.0.0/8 ! -i lo -j DROP

iptables -4 -A INPUT -m addrtype --dst-type BROADCAST -j DROP
iptables -4 -A INPUT -m addrtype --dst-type MULTICAST -j DROP
iptables -4 -A INPUT -m addrtype --dst-type ANYCAST -j DROP
iptables -4 -A INPUT -d 224.0.0.0/4 -j DROP
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP

iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

iptables -A INPUT -i lo -j ACCEPT

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables -N SSHBRUTE
iptables -A SSHBRUTE -m recent --name SSH --set
iptables -A SSHBRUTE -m recent --name SSH --update --seconds 300 --hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[SSH-brute]: "
iptables -A SSHBRUTE -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
iptables -A SSHBRUTE -j ACCEPT

iptables -N ICMPFLOOD
iptables -A ICMPFLOOD -m recent --set --name ICMP --rsource
iptables -A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit 1/sec --limit-burst 1 -j LOG --log-prefix "iptables[ICMP-flood]: "
iptables -A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP
iptables -A ICMPFLOOD -j ACCEPT

iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate NEW -j SSHBRUTE
iptables -A INPUT -p tcp --dport 22 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

iptables -A OUTPUT -p tcp -m multiport --sports 22,80,443 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

iptables -A INPUT -p tcp -m tcp -m multiport --dports 110,143,465,587,993,995 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -m tcp -m multiport --sport 110,143,465,587,993,995 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

iptables -A INPUT -p tcp --dport 25 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 25 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

iptables -A INPUT -p udp --dport 1900 -j DROP
iptables -A INPUT -p udp --sport 53 -j DROP

iptables -A INPUT -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[DOS]: "

iptables -4 -A INPUT -p icmp --icmp-type 0 -m conntrack --ctstate NEW -j ACCEPT
iptables -4 -A INPUT -p icmp --icmp-type 3 -m conntrack --ctstate NEW -j ACCEPT
iptables -4 -A INPUT -p icmp --icmp-type 11 -m conntrack --ctstate NEW -j ACCEPT

iptables -A INPUT -p tcp -s x.x.x.x --sport 1024:65535 -d x.x.x.x --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -s x.x.x.x --sport 3306 -d x.x.x.x --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 5 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --syn --dport 443 -m connlimit --connlimit-above 15 --connlimit-mask 32 -j REJECT --reject-with tcp-reset
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -m limit --limit 150/second --limit-burst 160 -j ACCEPT`


Rules for ipv6 (when enabled)

`::bash::ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT

ip6tables -6 -A INPUT -s ::1/128 ! -i lo -j DROP

ip6tables -A INPUT -m conntrack --ctstate INVALID -j DROP

ip6tables -A INPUT -i lo -j ACCEPT

ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

ip6tables -N SSHBRUTE
ip6tables -A SSHBRUTE -m recent --name SSH --set

ip6tables -A SSHBRUTE -m recent --name SSH --update --seconds 300
--hitcount 10 -m limit --limit 1/second --limit-burst 100 -j LOG
--log-prefix "iptables[SSH-brute]: "
ip6tables -A SSHBRUTE -m recent --name SSH --update --seconds 300 --hitcount 10 -j DROP
ip6tables -A SSHBRUTE -j ACCEPT

ip6tables -N ICMPFLOOD
ip6tables -A ICMPFLOOD -m recent --set --name ICMP --rsource

ip6tables -A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -m limit --limit 1/sec --limit-burst 1 -j LOG --log-prefix "iptables[ICMP-flood]: "
ip6tables -A ICMPFLOOD -m recent --update --seconds 1 --hitcount 6 --name ICMP --rsource --rttl -j DROP
ip6tables -A ICMPFLOOD -j ACCEPT

ip6tables -A INPUT -p tcp -m multiport --dports 80,443 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT

ip6tables -A OUTPUT -p tcp -m multiport --sports 80,443 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

ip6tables -A INPUT -p tcp -m tcp -m multiport --dports 110,143,465,587,993,995 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p tcp -m tcp -m multiport --sport 110,143,465,587,993,995 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

ip6tables -A INPUT -p tcp --dport 25 --syn -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
ip6tables -A OUTPUT -p tcp --sport 25 --syn -m conntrack --ctstate ESTABLISHED -j ACCEPT

ip6tables -A INPUT -p udp --dport 1900 -j DROP

ip6tables -A INPUT -p udp --sport 53 -j DROP

ip6tables -A INPUT -m limit --limit 1/second --limit-burst 100 -j LOG --log-prefix "iptables[DOS]: "

ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 1 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 3 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 4 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 133 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 134 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 135 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 136 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 137 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 141 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 142 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 130 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 131 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 132 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 143 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 148 -j ACCEPT
ip6tables -6 -A INPUT -p ipv6-icmp --icmpv6-type 149 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 151 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 152 -j ACCEPT
ip6tables -6 -A INPUT -s fe80::/10 -p ipv6-icmp --icmpv6-type 153 -j ACCEPT

ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -j ICMPFLOOD

ip6tables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -m limit --limit 150/second --limit-burst 160 -j ACCEPT`

Rules for ipv6 (when disabled)

`::bash::ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP`

Execute script to add rules to iptables

`sh -x iptables.sh`

If ip6tables rules failed, retry after switiching to legacy mode

`update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy`

!IMPORTANT: Before proceeding with next step, logout ssh session and try logging in to check iptables. If unable to login, restart instance to clear iptables rules and correct iptables. Make sure the rules were entered correctly.

To save the rules and restore it after every boot

`iptables-save > /etc/iptables.rules`

`ip6tables-save > /etc/ip6tables.rules`

`iptables-restore < /etc/iptables.rules`

`ip6tables-restore < /etc/ip6tables.rules`

To restore it automatically after reboot, add to cron jobs

`nano /etc/crontab`

`@reboot root iptables-restore < /etc/iptables.rules
@reboot root ip6tables-restore < /etc/ip6tables.rules`


III. Configuring Apache Server and SSL

To Set Hostname (replace example.com with your domain or a hostname, here we're using FQDN)

For aws-only

Set to preserve hostname on cloud init configs

`nano /etc/cloud/cloud.cfg`

`preserve_hostname: true`

Then set hostname

`hostnamectl set-hostname --static example.com`

For non-aws

Set hostname

`hostnamectl set-hostname example.com`

Configure ip with hosts (replace example.com and replace x.x.x.x [ipv4] and y:y:y:y:y:y:y [ipv6]).

`nano /etc/hosts`

`x.x.x.x example.com.example.com example.com
y:y:y:y:y:y:y example.com.example.com example.com`


Check Hostname

`hostname`

`hostname -f`

Set Localtime

`dpkg-reconfigure tzdata`


A. Installing Apache2

`apt update && apt upgrade`

`apt install apache2 apache2-doc apache2-utils libapache2-mod-security2 libapache2-mod-evasive`

Securing Apache

Add/Update following parameters on evasive config

nano /etc/apache2/mods-available/evasive.conf

`<IfModule mod_evasive20.c>
    DOSHashTableSize    3097
    DOSPageCount        5
    DOSSiteCount        50
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   3600
    DOSLogDir           "/var/log/apache2/"
</IfModule>`

To whitelist ip's, add following param (replace y.. with ipv4 or ipv6)

`DOSWhitelist y.y.y.y`

Enable security, evasive and headers module

`a2enmod security2`

`a2enmod evasive`

`a2enmod headers`

Edit apache conf and add or update following config

`nano /etc/apache2/apache2.conf`

`KeepAlive Off
ServerSignature Off
ServerTokens Prod`

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`

`::apacheconfig::<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/site/
    <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>
    RedirectMatch 301 ^((?!\/(.well-known\/acme-challenge\/)).*)$ https://example.com$1
</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`

Repeat the three step procedure to create multiple sites.
  • Create virtual config for site
  • Create directories for site
  • Enable site

B. Installing SSL

Install certbot client to obtain ssl from letsencrypt.com

`apt install certbot python-certbot-apache`

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

Use --rsa-key-size 3072 parameter to change key size

To test a certificate using staging environment before using production environment (optional)

`certbot certonly --staging --webroot --agree-tos -w /var/www/example.com/site -d example.com`

To get a production level certificate using webroot (Limited to 5 attempts/hr)

`certbot certonly --webroot --agree-tos -w /var/www/example.com/site -d example.com`

To get certificates for sub domains (optional)

`certbot certonly --webroot --agree-tos -w /var/www/example.com/site -d example.com -d www.example.com -w /var/www/sub.example.com/site -d sub.example.com`

Note down the path, similar to '/etc/letsencrypt/live/example.com/'

Check for four files having placed in /etc/letsencrypt/archive with 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`

To increase security, generate DH bit group

`openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048`

https://en.wikipedia.org/wiki/Key_size#Asymmetric_algorithm_key_lengths

"RSA claims that 1024-bit [asymmetric] keys are likely to become crackable some time between 2006 and 2010 and that 2048-bit keys are sufficient until 2030. An RSA key length of 3072 bits should be used if security is required beyond 2030. NIST key management guidelines further suggest that 15360-bit [asymmetric] RSA keys are equivalent in strength to 256-bit symmetric keys."

Add/update following ssl parameters to ssl module config

`nano /etc/apache2/mods-available/ssl.conf`

`::apacheconfig::SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol -all +TLSv1.3 +TLSv1.2
SSLHonorCipherOrder on
SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1
SSLOpenSSLConfCmd DHParameters "/etc/ssl/certs/dhparam.pem"
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingCache shmcb:/var/run/ocsp(128000)`

Enable ssl mod

`a2enmod ssl`

`systemctl restart apache2`

Append to vhost file to include ssl config (replace example.com)

`nano /etc/apache2/sites-available/example.com.conf`

`::apacheconfig::<VirtualHost *:443>
    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

    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"
</VirtualHost>`

Check ssl-rating for A+

In your browser:

`https://www.ssllabs.com/ssltest/analyze.html?d=example.com`

Install Cron for automated updates

`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`

`::bash::30 1 * * * /usr/bin/certbot renew >> /var/log/le-renew.log
35 1 * * * /bin/systemctl restart apache2`


IV. Installing PHP 7.3 and MariaDB

A. Installing PHP

PHP7.3 is available with Debian 10 repository

`apt install php7.3-cli php7.3-cgi php7.3-fpm php7.3-mysql php7.3-json php7.3-curl php7.3-mbstring php7.3-zip libapache2-mod-php7.3`

Link to other usable php extensions : https://www.php.net/manual/en/extensions.alphabetical.php

Securing PHP : Edit php.ini

`nano /etc/php/7.3/apache2/php.ini`
  • Set 0 for cgi.fix_pathinfo
  • Set 1 for session.referer_check
  • Set 1 for session.cookie_httponly
  • Set 128 for session.sid_length
  • Set 6 for session.sid_bits_per_character
  • Set 1 for session.use_strict_mode
  • Set 1 for session.cookie_secure
When using FCGI, edit php.ini in fpm update above changes

`nano /etc/php/7.3/fpm/php.ini`

For more session security settings visit the links below

http://php.net/manual/en/session.security.ini.php

https://medium.com/the-white-hat-elephpant/a-look-into-sessions-and-security-b6939a8f6e92

Set php defaults, enable fcgi modules and restart fpm 

`update-alternatives --set php /usr/bin/php7.3`

`a2enmod proxy_fcgi setenvif`

`a2enconf php7.3-fpm`

`systemctl restart php7.3-fpm`

Create a php page to test (optional) (replace example.com)

`nano /var/www/example.com/site/index.php`

`::php::<?php echo "Welcome to example.com"; die(); ?>`

To use FCGI for php, include following within ssl vhost (optional)

`::apacheconfig::<LocationMatch "(.*)\.(php)">
      ProxyPassMatch "unix:/var/run/php/php7.3-fpm.sock|fcgi://localhost/var/www/example.com/site/"
</LocationMatch>`

This is run all php scripts using FCGI proxy instead of Apache handler. Use phpinfo(); to check.


B. Installing MariaDB

`apt -y install mariadb-server mariadb-client`

Secure MariaDB (set Y for all and set root pass)

`mysql_secure_installation`

Check status of MariaDB

`systemctl status mariadb`

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)

`::sql::CREATE DATABASE db_name;`

`::sql::CREATE USER 'db_user'@'127.0.0.1' IDENTIFIED BY 'db_pass';`

`::sql::GRANT ALL PRIVILEGES ON db_name.* TO 'db_user'@'127.0.0.1';`

Check mysql.user table for limited user and flush.

`::sql::SELECT User, Host, plugin FROM mysql.user;`

`::sql::FLUSH PRIVILEGES;`

`\q`

Restart MariaDB and PHP to save changes

`service mariadb restart`

`systemctl restart php7.3-fpm`

C. Installing phpmyadmin

Get the latest pure binary file (.tar.gz) from https://www.phpmyadmin.net/downloads/

`wget https://files.phpmyadmin.net/phpMyAdmin/4.9.5/phpMyAdmin-4.9.5-all-languages.tar.gz`

`tar xvf phpMyAdmin-4.9.5-all-languages.tar.gz`

Move and rename the directory (replace 'nothingtosee')

`mv phpMyAdmin-4.9.5-all-languages /usr/share/`

`mv -T /usr/share/phpMyAdmin-4.9.5-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`

`::apacheconfig::<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.

If there are session based errors, provide full access to sessions folder

`chmod 777 /var/lib/php/sessions`


V. Setting up SFTP file access

Adding a limited access SFTP user to access site files (WIP)

Create a new group (replace example_group)

`groupadd example_group`

Add Limited User Account (replace example_user and enter password for user)

`adduser example_user`

Add limited_user to the group (For AWS only)

`adduser example_user example_group`

For AWS EC2, creating ssh keys is the only way now. Follow instructions given below to create ssh keys.

Mod limited_user to the group with root directory (For non-aws VPS providers DO, Linode, Vultr, etc..)

`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/example.com`

`chown -R example_user:example_group /var/www/example.com/site`

`chmod -R 755 /var/www/example.com`

`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)

`::bash::Subsystem sftp internal-sftp

Match Group example_group
ChrootDirectory /var/www/example.com
X11Forwarding no
AllowTcpForwarding no

ForceCommand internal-sftp`

Note: ChrootDirectory is the one that is writable only by root (usually, one less than user directory)

Adding Public Key Auth for SSH

Create keypair using terminal (for Linux only)

`ssh-keygen -t rsa -b 4096 -f ~/.ssh/example_user-example.com-ssh.key`


Install and open putty-keygen.exe (for Windows only)

Set bits to 4096 and option as SSH-2 RSA and generate

Enter passphrase, save public key, save private key, keep window open

Open putty application, add private key to 'putty connection > ssh > auth', save the session and open session with the desired user (limited/root) and enter password

Create new directory for auth key (non-aws vps)

`mkdir ~/.ssh; touch ~/.ssh/authorized_keys; chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys`

Create new directory for auth key (aws only)

`mkdir /home/example_user/.ssh; touch /home/example_user/.ssh/authorized_keys; chmod 700 /home/example_user/.ssh; chmod 600 /home/example_user/.ssh/authorized_keys; chown -R example_user:example_user /home/example_user/.ssh`


Edit the file and copy public key directly from keygen (or .pub file, if created from terminal) and paste here

For non-aws

`nano ~/.ssh/authorized_keys`

For aws

`nano /home/example_user/.ssh/authorized_keys`

Exit and rerun putty, load saved session of desired user. (for windows)

Make sure private key matches the saved public key for that user.

Restart ssh to confirm changes

`service ssh restart`

`systemctl restart apache2`

Try authenticating using Filezilla/Winscp to confirm access


VI. Optional commands


To Delete Limited User Account

`deluser --remove-home username`

To Delete any folders (created by mistake)

`rm -r -f /path/`

Restart PHP & Apache2

`systemctl restart php7.3-fpm apache2`

To revoke and remove ssl cert using certbot

`certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem`

`rm -rf /etc/certbot/archive/example.com/`

`rm -rf /etc/certbot/live/example.com/`

`rm -rf /etc/certbot/renewal/example.com.conf`


To add default permission to files created using acl

`apt install acl`

`setfacl -R -m d:u::rwx,d:g::rwx,d:o::rwx /var/www/example.com/site/777/`

To change mysql root pass (login to mysql first)

`mysql -u root -p`

`::sql::ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'password';`

To check Apache status and error log

`systemctl status apache2.service`

or

`tail -n 20 /var/log/apache2/error.log`


To install Memcached

`apt -y install memcached netcat`

Check and update configuration and enable memcached

`nano /etc/memcached.conf`

`systemctl restart memcached`

`systemctl enable memcached`

Check if working

`echo "stats settings" | nc localhost 11211`

Install php extension for memcached

`apt install -y php7.3-memcached`

Add memcached extension to php.ini & restart

`nano /etc/php/7.3/fpm/php.ini`

`extension=memcached`

`systemctl restart php7.3-fpm`

No comments