Bash скрипты: Защита веб-сервера от Ддос-атак

В этой статье мы разберем, как создать эффективный защитный периметр, используя только Bash, iptables, fail2ban и утилиты анализа логов. Вы получите готовые скрипты для внедрения на своих серверах.

Данная информация предназначена для услуг: VPS хостинг или Облачный хостинг

Понимание угрозы: какие DDoS-атаки блокирует Bash?

Прежде чем писать код, определим векторы атак, с которыми может справиться скриптовой подход.

Тип атаки Суть Эффективность защиты через Bash
SYN Flood Массовая отправка SYN-пакетов без завершения handshake Частичная (через настройки iptables и sysctl)
HTTP Flood Тысячи запросов к веб-странице (GET /) Высокая (анализ access.log + ограничение по User-Agent)
Slowloris Медленное открытие соединений Высокая (через модуль connlimit)
DNS Amplification Запросы к открытому DNS-резольверу Низкая (это проблема сети хостинга)
Brute-force SSH Перебор паролей по SSH Высокая (связка fail2ban + custom bash)

Скрипты не заменят специализированный Anti-DDoS аппаратный модуль, но позволят отсеять до 85% «мусорного» трафика на уровне L3-L7.

Важно: Все примеры ниже протестированы на CentOS 7/8, Ubuntu 20.04/22.04 и Debian 11/12.


Базовая настройка ядра Linux для смягчения атак

Прежде чем писать скрипты, нужно укрепить сам стек TCP/IP. Поместите следующие параметры в файл /etc/sysctl.d/99-ddos-protect.conf:
# Защита от SYN Flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_max_syn_backlog = 4096

# Ограничение таймаутов полуоткрытых соединений
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1

# Защита от ICMP-флуда (ping flood)
net.ipv4.icmp_echo_ignore_all = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Ограничение на количество одновременных соединений с одного IP
net.netfilter.nf_conntrack_max = 65536

Примените настройки:

sysctl -p /etc/sysctl.d/99-ddos-protect.conf

Скрипт для мониторинга SYN-RECV (bash):

#!/bin/bash
# watch_syn_flood.sh
LIMIT=500
CURRENT=$(ss -tan state syn-recv | grep -c "SYN-RECV")
if [ $CURRENT -gt $LIMIT ]; then
  echo "`date` - Обнаружен SYN Flood: $CURRENT полуоткрытых соединений" >> /var/log/ddos.log
  # Вызов подсистемы блокировки (см. раздел 5)
  /usr/local/bin/ddos_blocker.sh --syn
fi

Этот скрипт запускайте через cron каждые 30 секунд:

* * * * * sleep 30; /usr/local/bin/watch_syn_flood.sh

Скрипт для анализа access.log и блокировки HTTP-флуда

Самый распространенный способ положить сайт — это HTTP-флуд с подменой User-Agent. Напишем скрипт, который каждую минуту анализирует логи веб-сервера (nginx/apache) и блокирует подозрительные IP через iptables.

Алгоритм работы скрипта http_flood_detector.sh

  1. Определить временной диапазон (последние 60 секунд).

  2. Собрать IP-адреса, сделавшие более N запросов (для среднего хостинга N=200).

  3. Исключить доверенные IP (свой офис, поисковые боты).

  4. Добавить их в цепочку INPUT iptables с отклонением.

Полный код скрипта:
#!/bin/bash
# /usr/local/bin/http_flood_detector.sh

LOG_FILE="/var/log/nginx/access.log" # или /var/log/apache2/access.log
LIMIT_REQUESTS=200
BAN_TIME=600 # секунд (10 минут)
WHITELIST_FILE="/etc/ddos/whitelist.txt"
BLACKLIST_CHAIN="DDOS_HTTP"

# Создаем цепочку в iptables, если ее нет
iptables -L $BLACKLIST_CHAIN -n >/dev/null 2>&1
if [ $? -ne 0 ]; then
  iptables -N $BLACKLIST_CHAIN
  iptables -I INPUT -p tcp --dport 80,443 -j $BLACKLIST_CHAIN
fi

# Функция для логирования
log() {
  echo "[`date '+%Y-%m-%d %H:%M:%S'`] $1" >> /var/log/ddos_http.log
}

# Анализ логов за последнюю минуту
TIME_MARK=`date --date='1 minute ago' '+%d/%b/%Y:%H:%M'`
TMP_FILE=$(mktemp)

awk -v time="$TIME_MARK" '$4 ~ time {print $1}' $LOG_FILE | sort | uniq -c | sort -nr > $TMP_FILE

log "Анализ завершен. Обработано записей: $(wc -l < $TMP_FILE)"

# Загрузка белого списка
declare -A WHITELIST
while read ip; do
  WHITELIST["$ip"]=1
done < $WHITELIST_FILE

# Блокировка нарушителей
while read count ip; do
  if [ $count -gt $LIMIT_REQUESTS ] && [ -z "${WHITELIST[$ip]}" ]; then
  # Проверяем, не заблокирован ли уже
  iptables -L $BLACKLIST_CHAIN -n | grep -q "$ip"
  if [ $? -ne 0 ]; then
    iptables -A $BLACKLIST_CHAIN -s $ip -j DROP
    log "ЗАБЛОКИРОВАН $ip (запросов: $count)"
    # Добавляем автознятие блокировки
    (
      sleep $BAN_TIME
      iptables -D $BLACKLIST_CHAIN -s $ip -j DROP
      log "СНЯТА БЛОКИРОВКА $ip"
    ) &
  fi
fi
done < $TMP_FILE

rm -f $TMP_FILE

Настройка прав:
chmod 700 /usr/local/bin/http_flood_detector.sh
mkdir -p /etc/ddos
echo "127.0.0.1" > /etc/ddos/whitelist.txt
echo "8.8.8.8" >> /etc/ddos/whitelist.txt

Cron для запуска раз в минуту:
* * * * * /usr/local/bin/http_flood_detector.sh >/dev/null 2>&1

Ограничение количества соединений с одного IP (connlimit)

Бывает, что злоумышленник использует медленные атаки (Slowloris, RUDY) — создает тысячи соединений с сервером, но почти не передает данные. Здесь на помощь приходит модуль iptables connlimit. Напишем скрипт, который динамически устанавливает пороги.

Скрипт dynamic_conn_limit.sh

#!/bin/bash
# Устанавливает лимит на количество TCP-соединений с одного IP
# для портов 80,443,22,25

MAX_CONN=25 # Максимум соединений на IP
PORTS="80,443,22,25"
CHAIN_NAME="CONNLIMIT"

iptables -N $CHAIN_NAME 2>/dev/null
iptables -D INPUT -j $CHAIN_NAME 2>/dev/null
iptables -I INPUT -j $CHAIN_NAME

# Очистка старых правил
iptables -F $CHAIN_NAME

for PORT in ${PORTS//,/ }; do
  iptables -A $CHAIN_NAME -p tcp --dport $PORT -m connlimit \
    --connlimit-above $MAX_CONN --connlimit-mask 32 -j LOG --log-prefix "DDOS_CONNLIMIT: "

  iptables -A $CHAIN_NAME -p tcp --dport $PORT -m connlimit \
    --connlimit-above $MAX_CONN --connlimit-mask 32 -j DROP

  iptables -A $CHAIN_NAME -p tcp --dport $PORT -j ACCEPT
done

echo "Лимит соединений установлен: $MAX_CONN на IP"

Этот скрипт достаточно запустить один раз после перезагрузки (например, из /etc/rc.local). Однако для адаптивной защиты лучше поместить его в cron с проверкой текущей нагрузки: 

*/5 * * * * /usr/local/bin/dynamic_conn_limit.sh

Почему это эффективно? При DDoS-атаке с ботнета (5000 уникальных IP) каждый IP создает не более 25 соединений, что для сервера с 4 ГБ RAM является абсолютно безопасной нагрузкой. А настоящему пользователю 25 параллельных соединений на сайт — более чем достаточно.


Автоматическая блокировка по гео (geoip) с помощью bash + ipset

Атаки часто приходят из определенных стран. Если ваш проект работает только для РФ или Европы, можно отсечь весь трафик из других регионов на уровне ядра. Это снижает нагрузку на 70-90% во время массированной атаки.

Скрипт geoip_block.sh (использует базу MaxMind):
#!/bin/bash
# Блокирует все страны, кроме указанных

ALLOWED_COUNTRIES="RU UA BY KZ"
IPSET_NAME="geo_whitelist"

# Установка утилиты для работы с geoip
if ! command -v geoiplookup &> /dev/null; then
  apt-get install geoip-bin geoip-database -y
fi

# Создаем ipset
ipset create $IPSET_NAME hash:net 2>/dev/null

# Загружаем список всех разрешенных диапазонов
TMP_LIST="/tmp/allowed_nets.txt"
> $TMP_LIST

for COUNTRY in $ALLOWED_COUNTRIES; do
  echo "Загрузка диапазонов для $COUNTRY"
  wget -qO- "http://www.ipdeny.com/ipblocks/data/countries/$COUNTRY.zone" >> $TMP_LIST
done

# Заполняем ipset
while read net; do
  ipset add $IPSET_NAME $net 2>/dev/null
done < $TMP_LIST

# Применяем правило iptables
iptables -I INPUT -m set --match-set $IPSET_NAME src -j ACCEPT
iptables -I INPUT -p tcp --dport 80,443 -j DROP # Все, кроме белого списка

echo "Геоблокировка активирована. Разрешены: $ALLOWED_COUNTRIES"

Недостаток: база устаревает, требует обновления раз в месяц. Добавьте в cron:

0 0 1 * * /usr/local/bin/geoip_block.sh

Комплексный скрипт мониторинга и самолечения

Объединим все описанные выше модули в единую систему ddos_warden.sh. Он будет работать в фоне как демон (или через systemd).

Основной код комбайна

#!/bin/bash
# /usr/local/bin/ddos_warden.sh
# Демон для защиты от DDoS

CONFIG="/etc/ddos_warden.conf"
LOG="/var/log/ddos_warden.log"
PIDFILE="/var/run/ddos_warden.pid"

# Загрузка конфигурации по умолчанию
HTTP_LIMIT=200
SYN_LIMIT=500
CONN_LIMIT=30
BAN_TIME=600

[ -f $CONFIG ] && source $CONFIG

check_http() {
  local logfile="/var/log/nginx/access.log"
  [ ! -f $logfile ] && logfile="/var/log/apache2/access.log"
  [ ! -f $logfile ] && return

  local tm=$(date --date='1 minute ago' '+%d/%b/%Y:%H:%M')
  awk -v tm="$tm" '$4 ~ tm {print $1}' $logfile | sort | uniq -c | \
  while read cnt ip; do
    if [ $cnt -gt $HTTP_LIMIT ]; then
      if ! iptables -L INPUT -n | grep -q "$ip"; then
        iptables -A INPUT -s $ip -j DROP
        log "HTTP-FLOOD: blocked $ip ($cnt requests/min)"
      fi
    fi
  done
}

# Функция: контроль SYN-RECV
check_syn() {
  local syn_cnt=$(ss -tan state syn-recv | grep -c "SYN-RECV")
  if [ $syn_cnt -gt $SYN_LIMIT ]; then
    log "SYN FLOOD detected: $syn_cnt"
    # Включение syncookies на лету
    echo 1 > /proc/sys/net/ipv4/tcp_syncookies
  fi
}

# Функция: анализ системной нагрузки и автоснятие блокировок
check_load_and_clean() {
  local load=$(uptime | awk -F 'load average:' '{print $2}' | cut -d, -f1 | sed 's/ //g')
  if (( $(echo "$load < 0.5" | bc -l) )); then
    # При низкой нагрузке можно ослабить защиту
    iptables -F DDOS_HTTP 2>/dev/null
    log "Load is low ($load), flushing temporary bans"
  fi
}

# Функция: Логирования
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG
}

# Основной цикл
start_daemon() {
  echo $$ > $PIDFILE
  log "DDoS Warden started. Limits: HTTP=$HTTP_LIMIT, SYN=$SYN_LIMIT, CONN=$CONN_LIMIT"
  while true; do
    check_http
    check_syn
    check_load_and_clean
    sleep 30
  done
}

case "$1" in
  start)
    start_daemon &
    ;;
  stop)
    kill $(cat $PIDFILE)
    rm -f $PIDFILE
    log "DDoS Warden stopped"
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
esac

Установка как сервиса Systemd:
cat > /etc/systemd/system/ddos-warden.service <<EOF
[Unit]
Description=DDoS Protection Warden Service
After=network.target

[Service]
ExecStart=/usr/local/bin/ddos_warden.sh start
ExecStop=/usr/local/bin/ddos_warden.sh stop
Restart=always
User=root

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable ddos-warden
systemctl start ddos-warden

Логирование, отчетность и Grafana

Скрипты генерируют логи в /var/log/ddos*.log. Для визуализации атак и проверки эффективности напишем простой парсер в bash, который раз в час отправляет статистику в Telegram.

Скрипт ddos_report.sh:

#!/bin/bash
TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"


BLOCKED_IPS=$(grep "ЗАБЛОКИРОВАН" /var/log/ddos_http.log | tail -5 | paste -s -d ',' -)
TOTAL_BLOCKS=$(grep -c "ЗАБЛОКИРОВАН" /var/log/ddos_http.log)
LOAD=$(uptime | awk -F 'load average:' '{print $2}')

MESSAGE="???? *DDoS отчет за час*\nЗаблокировано IP: $TOTAL_BLOCKS\nТекущая нагрузка: $LOAD\nПоследние блокировки: $BLOCKED_IPS"

curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
-d chat_id=$CHAT_ID -d text="$MESSAGE" -d parse_mode="markdown"

Настройте cron:
0 * * * * /usr/local/bin/ddos_report.sh

Тестирование защиты (как убедиться, что скрипты работают)

Прежде чем доверить защиту продакшену, проведите тест на изолированном сервере или VPS с тестовым сайтом.

Инструменты для симуляции DDoS:

  • #hping3 (SYN flood):
    hping3 -S --flood --rand-source YOUR_IP -p 80
  • #ab (Apache Bench) для HTTP флуда:
    ab -n 10000 -c 500 http://YOUR_SITE/
  • #slowloris (Perl-скрипт):
    perl slowloris.pl -dns YOUR_SITE -port 80 -timeout 30 -num 500

Проверка блокировки:

iptables -L INPUT -n | grep DROP
tail -f /var/log/ddos_warden.log

Ожидаемый результат: через 1-2 минуты IP-адрес тестового клиента попадает в черный список, сайт перестает отвечать только для него, остальные пользователи работают штатно.

Ограничения и когда стоит переходить на профессиональный Anti-DDoS

Важно понимать: bash-скрипты не спасут от амплификационных атак (NTP, DNS, memcached) с трафиком 10+ Гбит/с. Сетевой канал обычного выделенного сервера просто переполнится, и скрипт даже не получит управление.

Когда нужен аппаратный или облачный Anti-DDoS:

  • Трафик атаки превышает 1 Гбит/с (предел гигабитного порта).

  • Атака на уровне L7 с ротацией User-Agent и подменой TLS fingerprint.

  • Целевой ресурс — онлайн-банкинг, биржа, госсайт (SLA 99.99%).

Однако для 90% проектов на shared hosting или VPS описанные скрипты позволяют выиграть время и сохранить доступность.

 
  • 0 Пользователи нашли это полезным

Помог ли вам данный ответ?

Ищете что-то другое?

xvps.ru