| Server IP : 172.67.201.108 / Your IP : 216.73.216.11 Web Server : Apache/2.4.68 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-69-123.ec2.internal 6.1.176-223.369.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Jul 24 13:34:27 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/banners/ |
Upload File : |
#!/bin/bash
# ============================================================
# Apache Security Hardening Setup Script
# Generated from broadwayworld.com production config
# Run as root: sudo bash apache-security-setup.sh
# ============================================================
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
info() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[SKIP]${NC} $1"; }
step() { echo -e "\n${GREEN}==>${NC} $1"; }
fail() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
# -----------------------------------------------------------
# Pre-flight checks
# -----------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
fail "This script must be run as root (use sudo)"
fi
if ! command -v httpd &>/dev/null; then
fail "Apache (httpd) not found on this system"
fi
APACHE_CONF_DIR="/etc/httpd/conf.d"
APACHE_ERROR_LOG="/etc/httpd/logs/error_log"
MPM=$(httpd -V 2>/dev/null | grep 'Server MPM' | awk '{print $3}')
echo "============================================================"
echo " Apache Security Hardening Setup"
echo "============================================================"
echo " Hostname: $(hostname)"
echo " Apache MPM: ${MPM:-unknown}"
echo " Date: $(date)"
echo "============================================================"
echo ""
read -p "Continue with setup? (y/N) " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 0
# -----------------------------------------------------------
# 1. Install fail2ban
# -----------------------------------------------------------
step "Installing fail2ban..."
if command -v fail2ban-client &>/dev/null; then
warn "fail2ban already installed"
else
if command -v yum &>/dev/null; then
yum install -y fail2ban
elif command -v apt-get &>/dev/null; then
apt-get update && apt-get install -y fail2ban
elif command -v dnf &>/dev/null; then
dnf install -y fail2ban
else
fail "No supported package manager found (yum/apt/dnf)"
fi
info "fail2ban installed"
fi
# -----------------------------------------------------------
# 2. Configure fail2ban jails
# -----------------------------------------------------------
step "Configuring fail2ban jails..."
if [[ -f /etc/fail2ban/jail.local ]]; then
warn "jail.local already exists — backing up to jail.local.bak"
cp /etc/fail2ban/jail.local /etc/fail2ban/jail.local.bak
fi
# Detect ban action based on what's available
if command -v nft &>/dev/null || rpm -q nftables &>/dev/null 2>&1; then
BAN_ACTION="nftables-multiport"
BAN_ACTION_ALL="nftables-allports"
elif command -v iptables &>/dev/null; then
BAN_ACTION="iptables-multiport"
BAN_ACTION_ALL="iptables-allports"
else
# fail2ban install usually pulls in nftables as a dependency
BAN_ACTION="nftables-multiport"
BAN_ACTION_ALL="nftables-allports"
fi
# Detect Apache error log location
if [[ -f /etc/httpd/logs/error_log ]]; then
ERROR_LOG="/etc/httpd/logs/error_log"
elif [[ -f /var/log/httpd/error_log ]]; then
ERROR_LOG="/var/log/httpd/error_log"
elif [[ -f /var/log/apache2/error.log ]]; then
ERROR_LOG="/var/log/apache2/error.log"
else
ERROR_LOG="/etc/httpd/logs/error_log"
warn "Could not detect error log path, defaulting to ${ERROR_LOG}"
fi
cat > /etc/fail2ban/jail.local << JAILEOF
[DEFAULT]
# Ban for 1 hour, escalate on repeat offenders
bantime = 3600
# Look at last 10 minutes of logs
findtime = 600
# Ban after 5 hits
maxretry = 5
banaction = ${BAN_ACTION}
banaction_allports = ${BAN_ACTION_ALL}
# ============================================================
# Apache scanner/probe detection (matches "Primary script unknown" etc.)
# ============================================================
[apache-noscript]
enabled = true
port = http,https
logpath = ${ERROR_LOG}
maxretry = 5
findtime = 60
bantime = 86400
# ============================================================
# Apache 404 flood detection (scanners spray random URLs)
# ============================================================
[apache-botsearch]
enabled = true
port = http,https
logpath = ${ERROR_LOG}
maxretry = 10
findtime = 60
bantime = 86400
# ============================================================
# Apache auth brute force
# ============================================================
[apache-auth]
enabled = true
port = http,https
logpath = ${ERROR_LOG}
maxretry = 5
findtime = 600
bantime = 3600
# ============================================================
# Repeat offenders - banned 3 times = 7 day ban on all ports
# ============================================================
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = ${BAN_ACTION_ALL}
bantime = 604800
findtime = 86400
maxretry = 3
JAILEOF
# Ensure fail2ban log exists (recidive jail needs it)
touch /var/log/fail2ban.log
info "fail2ban jails configured (ban action: ${BAN_ACTION})"
# -----------------------------------------------------------
# 3. Apache security hardening config
# -----------------------------------------------------------
step "Installing Apache security-hardening.conf..."
HARDENING_CONF="${APACHE_CONF_DIR}/security-hardening.conf"
if [[ -f "$HARDENING_CONF" ]]; then
warn "security-hardening.conf already exists — backing up"
cp "$HARDENING_CONF" "${HARDENING_CONF}.bak"
fi
cat > "$HARDENING_CONF" << 'HARDENEOF'
# ============================================================
# 1. Connection timeouts - kill slow/idle connections faster
# ============================================================
# Header: 20s initial, then must send at min 500 bytes/sec
# Body: 20s initial, then must send at min 500 bytes/sec
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
# ============================================================
# 2. Block common vulnerability scanner URL patterns
# ============================================================
<IfModule mod_rewrite.c>
RewriteEngine On
# Block common webshell/exploit probe filenames
RewriteCond %{REQUEST_URI} ^/(shell|c99|r57|wso|alfa|b374k|adminer|phpinfo|eval-stdin|wp-login)\.php [NC,OR]
RewriteCond %{REQUEST_URI} ^/(\.env|\.git|\.svn|\.htpasswd|web\.config|xmlrpc\.php) [NC,OR]
RewriteCond %{REQUEST_URI} ^/(vendor/phpunit|cgi-bin/luci|boaform|GponForm|TP/public|solr/) [NC,OR]
RewriteCond %{REQUEST_URI} ^/(config\.bak|database\.sql|db\.sql|dump\.sql|backup\.zip) [NC,OR]
RewriteCond %{REQUEST_URI} \.(cgi|asp|aspx|jsp|jspx)$ [NC]
RewriteRule ^ - [F,L]
</IfModule>
# ============================================================
# 3. Block empty/suspicious User-Agents
# ============================================================
<IfModule mod_rewrite.c>
# Block requests with no User-Agent (most scanners)
RewriteCond %{HTTP_USER_AGENT} ^$ [OR]
# Block known scanner tools
RewriteCond %{HTTP_USER_AGENT} (nikto|sqlmap|nmap|masscan|zgrab|nuclei|dirbuster|gobuster|ffuf|wpscan|acunetix|nessus|openvas) [NC]
RewriteRule ^ - [F,L]
</IfModule>
# ============================================================
# 4. Limit HTTP methods to what you actually use
# ============================================================
<Location "/">
<LimitExcept GET POST HEAD OPTIONS>
Require all denied
</LimitExcept>
</Location>
HARDENEOF
info "security-hardening.conf installed"
# -----------------------------------------------------------
# 4. MPM event tuning (if applicable)
# -----------------------------------------------------------
step "Checking MPM tuning..."
if [[ "$MPM" == "event" ]]; then
HTTPD_CONF="/etc/httpd/conf/httpd.conf"
if grep -q "mpm_event_module" "$HTTPD_CONF" 2>/dev/null; then
warn "mpm_event_module config already exists in httpd.conf"
else
# Check available RAM to size appropriately
TOTAL_RAM_MB=$(free -m | awk '/Mem:/{print $2}')
if [[ $TOTAL_RAM_MB -le 2048 ]]; then
SERVER_LIMIT=16
MAX_WORKERS=400
elif [[ $TOTAL_RAM_MB -le 4096 ]]; then
SERVER_LIMIT=32
MAX_WORKERS=800
else
SERVER_LIMIT=64
MAX_WORKERS=1600
fi
cat >> "$HTTPD_CONF" << MPMEOF
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
ServerLimit ${SERVER_LIMIT}
MaxRequestWorkers ${MAX_WORKERS}
MaxConnectionsPerChild 10000
</IfModule>
MPMEOF
info "MPM event config added (ServerLimit=${SERVER_LIMIT}, MaxRequestWorkers=${MAX_WORKERS})"
fi
# Also fix Timeout if it's too high
CURRENT_TIMEOUT=$(grep -P "^Timeout\s+" "$HTTPD_CONF" 2>/dev/null | awk '{print $2}')
if [[ -n "$CURRENT_TIMEOUT" && "$CURRENT_TIMEOUT" -gt 120 ]]; then
sed -i "s/^Timeout ${CURRENT_TIMEOUT}$/Timeout 60/" "$HTTPD_CONF"
info "Reduced Timeout from ${CURRENT_TIMEOUT}s to 60s"
else
warn "Timeout already reasonable (${CURRENT_TIMEOUT:-default}s)"
fi
CURRENT_PROXY_TIMEOUT=$(grep -P "^ProxyTimeout\s+" "$HTTPD_CONF" 2>/dev/null | awk '{print $2}')
if [[ -n "$CURRENT_PROXY_TIMEOUT" && "$CURRENT_PROXY_TIMEOUT" -gt 120 ]]; then
sed -i "s/^ProxyTimeout ${CURRENT_PROXY_TIMEOUT}$/ProxyTimeout 60/" "$HTTPD_CONF"
info "Reduced ProxyTimeout from ${CURRENT_PROXY_TIMEOUT}s to 60s"
else
warn "ProxyTimeout already reasonable (${CURRENT_PROXY_TIMEOUT:-default}s)"
fi
else
warn "MPM is '${MPM}', not event — skipping MPM tuning"
fi
# -----------------------------------------------------------
# 5. Kernel TCP tuning
# -----------------------------------------------------------
step "Applying kernel TCP tuning..."
SYSCTL_CONF="/etc/sysctl.d/99-apache-tuning.conf"
if [[ -f "$SYSCTL_CONF" ]]; then
warn "99-apache-tuning.conf already exists — backing up"
cp "$SYSCTL_CONF" "${SYSCTL_CONF}.bak"
fi
cat > "$SYSCTL_CONF" << 'SYSCTLEOF'
# Larger SYN backlog to handle bursts
net.ipv4.tcp_max_syn_backlog = 4096
# Fewer SYN-ACK retries (drop half-open connections faster)
net.ipv4.tcp_synack_retries = 2
# Shorter FIN timeout (reclaim closed connections faster)
net.ipv4.tcp_fin_timeout = 15
SYSCTLEOF
sysctl -p "$SYSCTL_CONF" 2>/dev/null
info "Kernel TCP settings applied and persisted"
# -----------------------------------------------------------
# 6. Validate and restart services
# -----------------------------------------------------------
step "Validating Apache config..."
if apachectl configtest 2>&1 | grep -q "Syntax OK"; then
info "Apache config syntax OK"
else
fail "Apache config test failed! Check manually with: apachectl configtest"
fi
step "Starting/restarting services..."
systemctl enable fail2ban 2>/dev/null
systemctl restart fail2ban
if fail2ban-client status &>/dev/null; then
JAIL_COUNT=$(fail2ban-client status | grep "Number of jail" | awk '{print $NF}')
info "fail2ban running with ${JAIL_COUNT} jails"
else
fail "fail2ban failed to start — check: journalctl -u fail2ban"
fi
echo ""
read -p "Restart Apache now to apply all changes? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
systemctl stop httpd
sleep 2
systemctl start httpd
if systemctl is-active httpd &>/dev/null; then
info "Apache restarted successfully"
else
fail "Apache failed to start! Check: journalctl -u httpd"
fi
else
warn "Apache NOT restarted — changes won't take full effect until you run:"
echo " sudo systemctl stop httpd && sleep 2 && sudo systemctl start httpd"
fi
# -----------------------------------------------------------
# Summary
# -----------------------------------------------------------
echo ""
echo "============================================================"
echo " Setup Complete"
echo "============================================================"
echo ""
echo " Installed:"
echo " - fail2ban with 4 jails (noscript, botsearch, auth, recidive)"
echo " - Apache security-hardening.conf (scanner blocks, timeouts)"
if [[ "$MPM" == "event" ]]; then
echo " - MPM event tuning (ServerLimit/MaxRequestWorkers)"
echo " - Timeout reduced to 60s"
fi
echo " - Kernel TCP tuning (SYN backlog, FIN timeout)"
echo ""
echo " Useful commands:"
echo " sudo fail2ban-client status # overview"
echo " sudo fail2ban-client status apache-noscript # see banned IPs"
echo " sudo fail2ban-client set apache-noscript unbanip <IP> # unban"
echo " sudo tail -f /etc/httpd/logs/error_log # watch errors"
echo "============================================================"