Setup LAMP Stack with hardened configuration - Debian 13

#!/bin/bash

# Run as root check
if [ "$(id -u)" -ne 0 ]; then
    echo "This script must be run as root."
    exit 1
fi

# Update system
echo "Updating the system..."
apt update && apt upgrade -y

# Install base packages
echo "Installing required packages: sudo, expect, openssh-server, composer, fail2ban, ufw, certbot..."
apt install -y sudo expect openssh-server composer fail2ban ufw certbot python3-certbot-apache apache2-utils

# Enable and start SSH
echo "Enabling and starting SSH server..."
systemctl enable ssh
systemctl start ssh
echo "SSH server is running."

# Prompt for new Linux user
read -p "Enter the new username: " NEW_USER

# Check if user already exists
if id "$NEW_USER" &>/dev/null; then
    echo "User $NEW_USER already exists. Exiting."
    exit 1
fi

# Prompt for password (used for Linux, MariaDB, and phpMyAdmin HTTP Auth)
read -sp "Enter password for $NEW_USER (used for Linux, MariaDB & phpMyAdmin Auth): " USER_PASS
echo

# Create Linux user and set password
adduser --gecos "" "$NEW_USER" --disabled-password
echo "$NEW_USER:$USER_PASS" | chpasswd
usermod -aG sudo "$NEW_USER"
echo "User $NEW_USER created and added to sudo group."

# Install Apache
echo "Installing Apache..."
apt install apache2 -y
systemctl start apache2
systemctl enable apache2
echo "Apache installed and running."

# Install MariaDB
echo "Installing MariaDB..."
apt install mariadb-server mariadb-client -y
systemctl start mariadb
systemctl enable mariadb
echo "MariaDB installed and running."

# Secure MariaDB using expect
echo "Securing MariaDB..."
SECURE_MYSQL=$(expect -c "
set timeout 10
spawn mysql_secure_installation
expect \"Enter current password for root (enter for none):\" { send \"\r\" }
expect \"Switch to unix_socket authentication\" { send \"n\r\" }
expect \"Change the root password?\" { send \"n\r\" }
expect \"Remove anonymous users?\" { send \"y\r\" }
expect \"Disallow root login remotely?\" { send \"y\r\" }
expect \"Remove test database and access to it?\" { send \"y\r\" }
expect \"Reload privilege tables now?\" { send \"y\r\" }
expect eof
")
echo "$SECURE_MYSQL"

# Create matching MariaDB user
echo "Creating MariaDB user '$NEW_USER'..."
mysql -e "CREATE USER '$NEW_USER'@'localhost' IDENTIFIED BY '$USER_PASS';"
mysql -e "GRANT ALL PRIVILEGES ON *.* TO '$NEW_USER'@'localhost' WITH GRANT OPTION;"
mysql -e "FLUSH PRIVILEGES;"
echo "MariaDB user '$NEW_USER' created with full privileges."

# Install PHP
echo "Installing PHP and extensions..."
apt install php libapache2-mod-php php-mysql php-intl -y

# Configure Apache to prioritize PHP
echo "Configuring Apache for PHP..."
sed -i "s/index.html/index.php index.html/" /etc/apache2/mods-enabled/dir.conf

# Allow Override for /var/www/
sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf

# Create test PHP file
echo "<?php phpinfo(); ?>" > /var/www/html/test.php
echo "PHP test file created at /var/www/html/test.php"

# Install phpMyAdmin silently
echo "Installing phpMyAdmin..."
export DEBIAN_FRONTEND=noninteractive
apt install phpmyadmin php-mbstring php-zip php-gd php-json php-curl -y
phpenmod mbstring
ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-available/phpmyadmin.conf
a2enconf phpmyadmin

# ==============================================================================
# HARDENING & SECURITY CONFIGURATIONS
# ==============================================================================
echo "Applying security hardening & bot protection..."

# 1. Hide Apache Version & Signature
sed -i 's/^ServerTokens .*/ServerTokens Prod/' /etc/apache2/conf-available/security.conf
sed -i 's/^ServerSignature .*/ServerSignature Off/' /etc/apache2/conf-available/security.conf

# 2. Add Security Headers & Disable Autoindex
a2enmod headers rewrite setenvif
a2dismod autoindex -f

cat << 'EOF' >> /etc/apache2/conf-available/security.conf

# Custom Security Headers
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
EOF

# 3. Block Bad Bots & Scanners via SetEnvIf & Require
cat << 'EOF' > /etc/apache2/conf-available/block-bad-bots.conf
# 1. Block Bad User-Agents
SetEnvIfNoCase User-Agent "(ahrefsbot|semrushbot|mj12bot|roguebot|python-requests|libwww-perl|curl|wget|nikto|sqlmap|nmap)" bad_bot

# 2. Block Access to Sensitive Files
SetEnvIfNoCase Request_URI "\.(env|git|htaccess|htpasswd|bash_history|sql|conf|bak)$" bad_file

<Location />
    <RequireAll>
        Require all granted
        Require not env bad_bot
        Require not env bad_file
    </RequireAll>
</Location>
EOF
a2enconf block-bad-bots

# 4. Protect phpMyAdmin with HTTP Basic Auth
htpasswd -bc /etc/apache2/.htpasswd "$NEW_USER" "$USER_PASS"

cat << 'EOF' > /etc/phpmyadmin/conf.d/security.conf
<Directory /usr/share/phpmyadmin>
    AuthType Basic
    AuthName "Restricted Access"
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
</Directory>
EOF

# Link phpMyAdmin security config if needed
if [ -f /etc/apache2/conf-available/phpmyadmin.conf ]; then
    if ! grep -q "AuthType Basic" /etc/apache2/conf-available/phpmyadmin.conf; then
        sed -i '/<Directory \/usr\/share\/phpmyadmin>/a \    AuthType Basic\n    AuthName "Restricted Access"\n    AuthUserFile \/etc\/apache2\/.htpasswd\n    Require valid-user' /etc/apache2/conf-available/phpmyadmin.conf
    fi
fi

# 5. Configure Fail2ban for Apache
cat << 'EOF' > /etc/fail2ban/jail.d/apache.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 3

[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-fakegooglebot]
enabled  = true
port     = http,https
logpath  = %(apache_access_log)s
maxretry = 1

[apache-shellshock]
enabled  = true
port     = http,https
logpath  = %(apache_error_log)s
maxretry = 1
EOF

systemctl restart fail2ban
systemctl restart apache2

# 6. Configure UFW Firewall
echo "Configuring UFW Firewall..."
ufw allow ssh
ufw allow http
ufw allow https
echo "y" | ufw enable

echo "Setup and hardening complete! System will reboot in 10 seconds..."
sleep 10
reboot