Всем привет!
Как-то писал скрипт для защиты от ддоса при помощи сервиса CloudFlare.
Но CloudFlare обновился, теперь там три режима:

- Полностью отключена фильтрация подозрительного трафика.
- Посетители не получают никаких челленджей от Cloudflare.
- Ноль защиты от ботов и атак на уровне security features (всё идёт напрямую).


- Минимальный уровень защиты.
- Только самые подозрительные IP/боты получат челлендж (JS или CAPTCHA).
- Легальный трафик почти всегда проходит без препятствий.


- Самый высокий уровень.
- Все пользователи (включая реальных) получают JavaScript-челлендж (5 секунд).
- Защита активируется до выполнения JS-кода, предотвращает доступ ботам/сканерам/LOIC и пр.
Напомню, скрипт запускается как демон и начинает мониторить число соединений nginx, apache и нагрузку на сервер раз в 3 секунды.
Если эти параметры превышают лимиты, то включается защита under_attack на пять минут.
Скрипт желательно запускать с повышенным приоритетом, например /usr/bin/nice -n -10.
Также в скрипте добавлена проверка, на установку нужного софта (Лучше для первого запуска, запустить скрипт вручную).
Чтобы скрипт мог подсчитывать число активных соединений, нужно включить ngx_http_stub_status_module. Обычно он собран по умолчанию, достаточно задать соответствующий location.
Пример добавления локейшена в конфигурацию Nginx (файл /etc/nginx/conf.d/status.conf (Нужно создать файл с содержимым ниже)):
Код:
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status; # Включаем модуль
allow 127.0.0.1; # Разрешаем доступ только с localhost
deny all; # Остальным запрещаем
}
}
Теперь метрика будет доступна по адресу
Чтобы увидеть нужно авторизоваться или зарегистрироваться.
Для остановки скрипта, нужно создать файл /tmp/cloudflare_monitor_stop.
Сам скрипт:
Bash:
#!/bin/bash
# cloudflare_load_monitor_v4.sh (rev-2025-05-07)
#
# Включает Under-Attack-mode Cloudflare ТОЛЬКО после
# – 5-кратного подряд превышения CPU-порога
# – 5-кратного подряд превышения порога активных коннектов Nginx
# – 5-кратного подряд превышения порога активных коннектов Apache
# -------------------------------------------------------------
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
######################## Cloudflare ##########################
CF_API_TOKEN="Insert_real token" # TODO: real token
ZONE_ID="Insert_zone_id" # TODO: real zone_id
DEFAULT_SECURITY_LEVEL="essentially_off" # off | essentially_off
SECURITY_LEVEL_ATTACK="under_attack" # включаем этот режим
######################## Пороги/интервалы ####################
CPU_THRESHOLD=95
CONN_THRESHOLD=2000 # Nginx
APACHE_CONN_THRESHOLD=120 # Apache
CHECK_INTERVAL=5 # сек
ATTACK_DURATION=300 # сек Under-Attack
NGINX_STATUS_URL="http://127.0.0.1/nginx_status"
APACHE_PORT=8080
APACHE_PROCESS_NAME="apache2"
EMAIL_TO="Insert_email"
LOG_FILE="/var/log/cloudflare_load_monitor.log"
######################## Функции утилиты #####################
log(){ echo "$(date '+%F %T') $1" | tee -a "$LOG_FILE" >&2; }
send_email(){ echo "$2" | mail -s "$1" "$EMAIL_TO"; }
set_cf_security_level(){
local level="$1"
log "Cloudflare → ${level}"
curl -s -X PATCH \
"https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/security_level" \
-H "Authorization: Bearer ${CF_API_TOKEN}" \
-H "Content-Type: application/json" \
--data "{\"value\":\"${level}\"}" | tee -a "$LOG_FILE"
}
get_cpu_usage(){
local idle
idle=$(LANG=C mpstat 1 1 | awk '/Average/ {print $(NF)}')
printf "%.0f" "$(echo "${idle:-100}" | awk '{print 100-$1}')"
}
get_nginx_conn(){
local st
st=$(curl -s "$NGINX_STATUS_URL")
[[ -z $st || $st != *"Active connections:"* ]] \
&& { log "Nginx status недоступен"; echo $((CONN_THRESHOLD+1)); } \
|| echo "$st" | awk '/Active connections/ {print $3}'
}
get_apache_conn(){
ss -tanp | awk -v p="$APACHE_PORT" -v n="$APACHE_PROCESS_NAME" '
$1=="ESTAB" && $4 ~ ":"p"$" && $0 ~ n {c++} END{print c+0}'
}
##################### Проверка окружения #####################
# полный список утилит, от которых зависит скрипт
REQUIRED_CMDS=(curl mpstat jq mail ss awk bc)
for cmd in "${REQUIRED_CMDS[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
log "Ошибка: требуемая утилита '$cmd' не найдена. Установите её и перезапустите."
exit 1
fi
done
# Проверяем доступность status-страницы nginx
if ! curl -s "$NGINX_STATUS_URL" | grep -q "Active connections"; then
log "Ошибка: Nginx status-страница недоступна по $NGINX_STATUS_URL"
exit 1
fi
####################### Счётчики превышений ###################
CPU_EXCEED_COUNT=0
NGINX_EXCEED_COUNT=0
APACHE_EXCEED_COUNT=0
log "★ Старт мониторинга Cloudflare. PID $$"
######################## Главный цикл ########################
while true; do
[[ -f /tmp/cloudflare_monitor_stop ]] && {
log "Stop-файл найден. Завершение."; rm -f /tmp/cloudflare_monitor_stop; exit 0; }
CPU_USAGE=$(get_cpu_usage)
NGINX_CONN=$(get_nginx_conn)
APACHE_CONN=$(get_apache_conn)
log "CPU: ${CPU_USAGE}% | Nginx: ${NGINX_CONN} | Apache: ${APACHE_CONN}"
TRIGGER_CPU=0; TRIGGER_NGINX=0; TRIGGER_APACHE=0
# --- CPU ---
if (( CPU_USAGE > CPU_THRESHOLD )); then
((CPU_EXCEED_COUNT++))
log "CPU порог превышен: ${CPU_EXCEED_COUNT}/5"
[[ $CPU_EXCEED_COUNT -ge 5 ]] && { TRIGGER_CPU=1; CPU_EXCEED_COUNT=0; }
else CPU_EXCEED_COUNT=0; fi
# --- Nginx ---
if [[ $NGINX_CONN =~ ^[0-9]+$ && $NGINX_CONN -gt $CONN_THRESHOLD ]]; then
((NGINX_EXCEED_COUNT++))
log "Nginx порог превышен: ${NGINX_EXCEED_COUNT}/5"
[[ $NGINX_EXCEED_COUNT -ge 5 ]] && { TRIGGER_NGINX=1; NGINX_EXCEED_COUNT=0; }
else NGINX_EXCEED_COUNT=0; fi
# --- Apache ---
if [[ $APACHE_CONN =~ ^[0-9]+$ && $APACHE_CONN -gt $APACHE_CONN_THRESHOLD ]]; then
((APACHE_EXCEED_COUNT++))
log "Apache порог превышен: ${APACHE_EXCEED_COUNT}/5"
[[ $APACHE_EXCEED_COUNT -ge 5 ]] && { TRIGGER_APACHE=1; APACHE_EXCEED_COUNT=0; }
else APACHE_EXCEED_COUNT=0; fi
# --- триггер ---
if (( TRIGGER_CPU || TRIGGER_NGINX || TRIGGER_APACHE )); then
REASON=""
((TRIGGER_CPU)) && REASON+="CPU>${CPU_THRESHOLD}% ×5. "
((TRIGGER_NGINX)) && REASON+="Nginx>${CONN_THRESHOLD} ×5. "
((TRIGGER_APACHE)) && REASON+="Apache>${APACHE_CONN_THRESHOLD} ×5. "
log "► UNDER_ATTACK: $REASON"
send_email "Cloudflare Under-Attack ON" "$REASON"
set_cf_security_level "$SECURITY_LEVEL_ATTACK"
SECONDS_PASSED=0
while (( SECONDS_PASSED < ATTACK_DURATION )); do
sleep 10
((SECONDS_PASSED+=10))
[[ -f /tmp/cloudflare_monitor_stop ]] && {
log "Stop-файл в режиме атаки. Завершение."
rm -f /tmp/cloudflare_monitor_stop; exit 0; }
done
log "◄ Возврат в нормальный режим (${DEFAULT_SECURITY_LEVEL})"
set_cf_security_level "$DEFAULT_SECURITY_LEVEL"
send_email "Cloudflare Under-Attack OFF" "Режим 'under_attack' снят."
fi
sleep "$CHECK_INTERVAL"
done
После запуска в /var/log/cloudflare_load_monitor.log будут логи работы скрипта.
Рекомендую сделать ротацию через logrotate, иначе сильно разрастется, сделать можно так:
Чтобы лог-файл /var/log/cloudflare_load_monitor.log не разрастался бесконечно, нужно настроить ротацию через logrotate.
Создайте файл /etc/logrotate.d/cloudflare_load_monitor со следующим содержимым:
Код:
/var/log/cloudflare_load_monitor.log {
daily
rotate 7
compress
missingok
notifempty
create 644 root root
sharedscripts
postrotate
endscript
}
Теперь система будет автоматически ротировать лог раз в день, храня до 7 сжатых архивов.
Также можно создать скрипт мониторинга работы нашего скрипта:
Bash:
#!/bin/bash
# monitor_cloudflare_monitor.sh
#
# Этот скрипт проверяет, запущен ли основной скрипт мониторинга (cloudflare_load_monitor.sh).
# Если монитор не запущен, он запускает его с повышенным приоритетом и логирует событие.
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LOG_FILE="/var/log/cloudflare_monitor_supervisor.log"
MONITOR_SCRIPT="/var/local/cloudflare_load_monitor.sh"
# Функция логирования
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}
# Имя процесса: можно искать по имени скрипта
PROCESS_COUNT=$(pgrep -fc "$(basename "$MONITOR_SCRIPT")")
if [ "$PROCESS_COUNT" -eq 0 ]; then
log "Основной скрипт мониторинга не найден. Запускаем его с повышенным приоритетом."
# Запускаем с повышенным приоритетом. Здесь используется nice с значением -10.
# Запускаем в фоне и перенаправляем вывод в лог.
nohup nice -n -10 "$MONITOR_SCRIPT" >/dev/null 2>&1 &
sleep 5 # Подождем немного, чтобы процесс стартовал.
log "Скрипт мониторинга запущен. PID: $!"
else
log "Скрипт мониторинга уже запущен (процессов: ${PROCESS_COUNT})."
fi
И добавить его в планировщик, раз в минуту:
Код:
crontab -e
* * * * * /usr/bin/nice -n -10 /bin/bash /var/local/monitor_cloudflare_monitor.sh
Получение Cloudflare API Token
- Зайдите в свою учётную запись на
Чтобы увидеть нужно авторизоваться или зарегистрироваться.
- Нажмите Create Custom Token.
- Укажите необходимые Permissions:
- Zone: Zone Settings: Edit
- Выберите нужные Zone Resources:
- Include > Specific zone (или All zones, если нужно для всех доменов).
- Сохраните настройки и создайте токен.
- Скопируйте полученный токен и сохраните в безопасном месте (после создания полностью скопировать его можно будет только один раз!).
- Таже нужен будет Account ID вашего домена, его можно увидеть в правой панели тут на вкладке Overview.
Удачи!)