====Install CentOS 8 LAMP stack====
This is install a LAMP stack on CentOS 8 with virtual host support, PHP, fail2ban, SSH security, letsencrypt, auto updates.
Install CentOS 8 minimal with 2 CPU, 512MB+ RAM, 20GB+ storage, set FQDN, set static IP, enable NTP.
3.) After install if finished reboot -> login -> perform a "dnf update".
==Create limited user account and add to wheel group for sudo==
useradd example_user && passwd example_user
usermod -aG wheel example_user
==Install dependencies and vim==
dnf install unzip wget vim tar
Logout of root and login using sudo user
==Disallow root login over SSH==
sudo vim /etc/ssh/sshd_config
then set
PermitRootLogin no
==Generate SSH key for sudo user on client computer (not the webserver)==
To help keep things organized we'll create a keypair that is specific to the user and the remote sudo user+host. \\
https://www.ssh.com/ssh/keygen/
ssh-keygen -C "your_email@example.com" -f ~/.ssh/your_email@example.com-remote_sudo_username_@remote_hostname -t ed25519
Record the private and public keys in a secure document for the webserver. \\
Copy the public key to the remote webserver. \\
ssh-copy-id -i ~/.ssh/your_email@example.com-remote_sudo_username_@remote_hostname.pub sudo_username@remote_hostname
sudo vim /etc/ssh/sshd_config
then set
PasswordAuthentication no
Restart sshd
sudo systemctl restart sshd
Login using SSH key
ssh -i deployment_key.txt demo@192.237.248.66
https://www.tecmint.com/install-lamp-on-centos-8/
https://linuxize.com/post/how-to-install-php-on-centos-8/
https://www.linode.com/docs/web-servers/lamp/how-to-install-a-lamp-stack-on-centos-8/
https://www.linode.com/docs/web-servers/apache/how-to-install-and-configure-fastcgi-and-php-fpm-on-centos-8/
https://www.digitalocean.com/community/tutorials/how-to-run-multiple-php-versions-on-one-server-using-apache-and-php-fpm-on-ubuntu-18-04
https://certbot.eff.org/lets-encrypt/centosrhel8-apache.html
====Install Apache====
==Configure hosts==
sudo vim /etc/hosts
Add a line for your FQDN
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.10.30 websrv01.domainname.com websrv01
sudo dnf install httpd httpd-tools
sudo systemctl enable httpd
sudo systemctl start httpd
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
====Install MariaDB====
sudo dnf install mariadb-server mariadb
sudo systemctl enable mariadb
sudo systemctl start mariadb
sudo mysql_secure_installation
====Install PHP====
sudo dnf install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm
sudo dnf module reset php
sudo dnf module enable php:remi-8.2
sudo dnf install php php-opcache php-gd php-curl php-mysqlnd mod_fcgid
sudo systemctl enable php-fpm
sudo systemctl start php-fpm
Increase upload and post size limit for PHP
sudo vim /etc/php.ini
Modify the following lines to meet your requirements
upload_max_filesize = 50M ;
post_max_size = 50M ;
==Create php PHP pools for each site==
Note: isn't taking full advantage of the feature, feel free to research more if needed.
sudo cp /etc/php-fpm.d/www.conf /etc/php-fpm.d/example.com.conf
Edit the file to change the socket name, user and group, and socket listen address. Ensure that the listen address is different from the listen address that you set in the main PHP pool configuration file. You can append the name of your site as part of the file name, for example, listen = /var/run/php-fpm/example.com.sock. Also, ensure that you comment out or replace any existing user and group and add your own user and group settings as shown in the example.
sudo vim /etc/php-fpm.d/example.com.conf
; Start a new pool named 'www'.
; the variable $pool can be used in any directive and will be replaced by the
; pool name ('www' here)
[www]
...
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = apache
group = apache
...
listen = /var/run/php-fpm/www.sock
Note: you can replace each instance of www with example.domain.com by using the following in vim:
:g/www/s//example\.domain\.com/g
The $s searches through the whole file, the \. is needed because . is a special regex pattern and the \ escapes it... though I'm still not entirely sure what escapes is; regex to me is like cooking or playing music, magic.
====Create Virtual Hosts====
==Create directories for sites==
sudo mkdir -p /var/www/html/site1.your_domain/public_html
sudo mkdir -p /var/www/html/site2.your_domain/public_html
==Set Permissions==
sudo chown -R apache:apache /var/www/html/site1.your_domain/public_html
sudo chown -R apache:apache /var/www/html/site2.your_domain/public_html
sudo chmod -R 755 /var/www/html/site1.your_domain/public_html
sudo chmod -R 755 /var/www/html/site2.your_domain/public_html
Create a file in each site to test webserver and show php version
sudo vim /var/www/html/site1.your_domain/public_html/info.php
Add
==Setup virtual host config files==
sudo vim /etc/httpd/conf.d/site1.your_domain.conf
Add the following content. Make sure the website directory path, server name, and PHP version match your setup:
Require all granted
Options -Indexes -MultiViews -Includes -FollowSymLinks
ServerAdmin webmaster@example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/html/example.com/public_html
ErrorLog /var/log/httpd/example.com_error.log
CustomLog /var/log/httpd/example.com_access.log combined
DirectoryIndex index.php
Options +ExecCGI
FcgidConnectTimeout 20
AddType application/x-httpd-php .php
AddHandler application/x-httpd-php .php
Alias /php7-fcgi /usr/lib/cgi-bin/php7-fcgi
ProxyPassMatch " ^/(.*\.php(/.*)?)$" "unix:/run/php-fpm/example.com.sock|fcgi://localhost/var/www/html/example.com/public_html/"
Save and close the file when you are finished. Then check the Apache configuration file for any syntax errors:
sudo httpd -t
You’ll see the following output:
Output
Syntax OK
==Disable Exposing Apache Server Info==
https://www.if-not-true-then-false.com/2009/howto-hide-and-modify-apache-server-information-serversignature-and-servertokens-and-hide-php-version-x-powered-by/ \\
This will help to prevent being the target of a an attack if you're running an out of date or vunerable release
sudo vim /etc/httpd/conf/httpd.conf
Add the following:
ServerSignature Off
ServerTokens Prod
==Disable Exposing PHP Version Info==
And add your timezone...
sudo vim /etc/php.ini
Change the following:
expose_php = Off
date.timezone = America/Los_Angeles
Finally, restart the Apache service and PHP-FPM to implement your changes:
sudo systemctl restart httpd
sudo systemctl restart php-fpm
Now that you have configured Apache to serve each site, you will test them to make sure the proper PHP versions are running.
test.example.com/info.php
delete the info.php after your'e done.
delete the welconf.conf to disable the default apache welcome page.
sudo rm /etc/httpd/conf.d/welcome.conf
==Remove Default Access from httpd.conf==
This is important as it would allow access to the /var/www/html path via HTTP.
sudo vim /etc/httpd/conf/httpd.conf
Modify the following statements to mirror the examples below:
DocumentRoot "/var/www/html"
AllowOverride None
Require all denied
Options None
AllowOverride None
Require all denied
Options None
AllowOverride None
Require all denied
Options None
====Letsencrypt====
==Install certbot==
wget https://dl.eff.org/certbot-auto
sudo mv certbot-auto /usr/local/bin/certbot-auto
sudo chown root /usr/local/bin/certbot-auto
sudo chmod 0755 /usr/local/bin/certbot-auto
Generate local certificates
sudo /usr/libexec/httpd-ssl-gencerts
Request and install certificates for virtual hosts
sudo /usr/local/bin/certbot-auto --apache
When prompted enabled Redirect so all requests go over https
Enable autorenew via crontab
echo "0 0,12 * * * root python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && /usr/local/bin/certbot-auto renew -q" | sudo tee -a /etc/crontab > /dev/null
====OR... Certificate manually via CA====
Enable SSL Apache
https://www.thesslstore.com/knowledgebase/ssl-generate/generate-csr-apache-web-server-using-openssl-v-2/
https://forums.centos.org/viewtopic.php?t=43230
https://www.getpagespeed.com/server-setup/ssl-directory
Install Mod SSL
sudo dnf install mod_ssl
sudo /usr/libexec/httpd-ssl-gencerts
==Create Private Key and CSR==
sudo openssl req -new -newkey rsa:4096 -nodes -keyout site1.domain.com.key -out site1.domain.com.csr
Move the files to your PKI folder
sudo mv site1.domain.com.key /etc/pki/tls/private/
Set permissions on private key
sudo chown root:root /etc/pki/tls/private/site1.domain.com.key
sudo chmod 600 /etc/pki/tls/private/site1.domain.com.key
sudo restorecon -RvF /etc/pki/tls/private/
Submit the CSR to your CA (public or private)
Copy the BASE64 certificate from your CA to your cert folder
sudo vim /etc/pki/tls/certs/site1.domain.com.crt
Create the CA bundle associated with your certificate
sudo vim /etc/pki/tls/certs/site1.domain.com.ca-bundle
Paste the subordinate followed by the root BASE64 certificates
Edit the conf file for you website and change
DocumentRoot /var/www/html/site1.domain.com/public_html
ServerName site1.domain.com
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/site1.domain.com.crt
SSLCertificateKeyFile /etc/pki/tls/private/site1.domain.com.key
SSLCertificateChainFile /etc/pki/tls/certs/site1.domain.com.ca-bundle
....
....
....
==Disable HTTP in Firewall==
Do this only if you aren't using Letsencrypt for SSL/TLS
sudo firewall-cmd --remove-service=http --permanent
sudo firewall-cmd --reload
Or.... if you want to leave http open and have the client automatically redirected to https add this to your website.conf file, below the existing Virtual Host block (add a new one):
ServerName site1.domain.com
RewriteEngine on
RewriteCond %{SERVER_NAME} =site1.domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
Restart Apache
sudo systemctl restart httpd
Note: if you are using your own internal CA you'll need to import the root and any intermediate certificates into your browsers/etc.
====Install Postfix====
This is a send only SMTP server, create your public DNS records first. Then setup a virtual host for the domain of the mail server as this will allow us to use Letsencrypt certificates on the mail server. So if your smtp server is going to be mail.subdomain.domain.com then setup a virtual host to match that first then use certbot to get a letsencrypt certificate for that virtual host. We don't open any firewall rules to allow smtp traffic in as this will only send out messages from the host it runs on or the private subnets it's attached to.
==Install Postfix + mailx==
sudo dnf install postfix mailx
sudo systemctl enable postfix
sudo systemctl start postfix
sudo systemctl status postfix
==Configure Postfix==
This will configure it as a send only SMTP server
http://www.postfix.org/STANDARD_CONFIGURATION_README.html#local_network
sudo vim /etc/postfix/main.cf
Modify the following lines to match your domain/subnet
mydomain = subdomain.domain.com
myorigin = $mydomain
mynetworks = 127.0.0.0/8, 10.0.0.0/24, localhost
Restart Postfix
sudo systemctl restart postfix
Test sending an E-Mail
echo "Test Message" | mailx -s "Test Subject" recipient@somewhere.com
==Letsencrypt certificates for Postfix==
https://www.geekyramblings.net/2019/04/12/lets-encrypt-and-postfix/
sudo vim /etc/postfix/main.cf
Set the following variables
smtp_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtp_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
#smtp_tls_CApath = /etc/ssl/certs
#smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
#smtpd_tls_CApath = /etc/ssl/certs
#smtpd_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
Restart postfix
sudo systemctl restart postfix
Test sending an E-Mail again
echo "Test Message 2" | mailx -s "Test Subject 2" recipient@somewhere.com
I haven't validated the TLS certificates but everything appears to be working. For a full test you'll likely need to have a working reply to email to have the results sent back.
==Create Script to Reload Postfix==
sudo vim /etc/letsencrypt/renewal-hooks/reload_postfix
Add the following
!/bin/sh
for domain in $RENEWED_DOMAINS; do
case $domain in
subdomain.domain.com)
cd /etc/letsencrypt/live/$domain
chgrp letsencrypt *.pem
chmod 640 *.pem
/sbin/service postfix reload > /dev/null
;;
esac
done
Set permissions
sudo chmod 755 /etc/letsencrypt/renewal-hooks/reload_postfix
Setup a dedicated user for sending E-mail, use no_reply or similar so people get the picture. Use this info for SMTP authentication for your sending applications.
useradd no_reply && passwd no_reply
====Automatic Updates for CentOS====
https://www.tecmint.com/dnf-automatic-install-security-updates-automatically-in-centos-8/
sudo dnf install dnf-automatic
sudo vim /etc/dnf/automatic.conf
Set:
upgrade_type = security
download_updates = yes
apply_updates = yes
system_name = (your system name)
emit_via = motd
Enable the auto-update timer
sudo systemctl enable --now dnf-automatic.timer
====fail2ban====
https://idroot.us/install-fail2ban-centos-8/
https://www.digitalocean.com/community/tutorials/how-to-protect-an-apache-server-with-fail2ban-on-ubuntu-14-04
sudo dnf install fail2ban
==Create a Jail for SSHd==
sudo vim /etc/fail2ban/jail.d/sshd.local
Add the following:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
[selinux-ssh]
enabled = true
port = ssh
logpath = %(auditd_log)s
==Create a Jail for Apache==
sudo vim /etc/fail2ban/jail.d/apache.local
Add the following:
[apache-auth]
enabled = true
port = http,https
logpath = %(apache_error_log)s
[apache-badbots]
enabled = true
port = http,https
logpath = %(apache_access_log)s
bantime = 48h
maxretry = 1
[apache-noscript]
enabled = true
port = http,https
logpath = %(apache_error_log)s
[apache-overflows]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
[apache-nohome]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
[apache-botsearch]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
[apache-modsecurity]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 2
[apache-shellshock]
enabled = true
port = http,https
logpath = %(apache_error_log)s
maxretry = 1
sudo systemctl start fail2ban
sudo systemctl enable fail2ban
sudo fail2ban-client status sshd