MAATRIX / Блог / Счёт за трафик вырос втрое: кто качает ваши файлы

Счёт за трафик вырос втрое: кто качает ваши файлы

MAATRIX

Счёт за трафик вырос в два-три раза, а сайт вроде бы не менялся: тот же контент, те же посетители по аналитике. Прежде чем звонить в поддержку хостера с жалобой на «неправильный биллинг», откройте access-логи — в 90% случаев ответ там. Кто-то отдаёт ваши файлы через свою страницу, кто-то раздал прямую ссылку на закрытый контент, а кто-то методично скачивает весь каталог ботом. Ниже — как найти источник за 20 минут и закрыть его без ущерба для реальных посетителей.

Сначала разделите причины: рост бывает разный

Прежде чем защищаться, нужно понять, от чего именно. Смешивать сценарии — плохая идея: защита от одного может убить легитимный трафик от другого.

  • Легитимный рост. Статью расшарили, видео попало в подборку, магазин попал в топ выдачи. Трафик растёт вместе с уникальными посетителями и просмотрами страниц, распределён по многим IP и User-Agent, referrer — реальные соцсети и поисковики. Это хорошая проблема, её решают масштабированием, а не блокировками.
  • Хотлинк (hotlinking). Чужой сайт или форум вставил <img src="https://ваш-домен/файл.jpg"> или <video src=...> напрямую в свою разметку. Ваш сервер отдаёт байты, чужой сайт получает картинку бесплатно, а полосу и деньги платите вы. Классика — форумы, маркетплейсы объявлений, агрегаторы, где пользователи вставляют прямые ссылки на чужие изображения.
  • Утечка прямых ссылок на закрытый контент. У вас есть платные PDF, архивы для клиентов, файлы за paywall — и кто-то выложил прямую ссылку в открытый Telegram-канал, форум варезников или закешировал её в поисковике. Ссылка «непубличная», но не защищена ничем, кроме незнания URL.
  • Боты-скрейперы и парсеры. Автоматический обход всего каталога файлов — конкуренты собирают базу товаров с картинками, агрегаторы контента, LLM-краулеры, которые индексируют всё подряд ради обучающих датасетов. Отличаются от поисковых ботов тем, что не уважают robots.txt и качают тяжёлые файлы, а не только HTML.

Дальше — как отличить эти сценарии друг от друга по логам, а не гадать.

Access-логи: находим, кто именно качает

Если у вас nginx с форматом логов по умолчанию, в строке уже есть всё нужное: IP, запрошенный путь, referrer, User-Agent, код ответа, размер отданных байт. Если размер ответа не пишется — добавьте его.

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                 '$status $body_bytes_sent "$http_referer" '
                 '"$http_user_agent" $request_time';

Первым делом смотрим, кто вообще потребляет больше всего мегабайт — не запросов, а именно байт. Частая ошибка — считать по количеству хитов, а не по объёму: 500 запросов к HTML весят меньше, чем 20 запросов к видео.

# топ IP по отданным байтам за сегодняшний лог
awk '{sum[$1]+=$10} END {for (ip in sum) print sum[ip], ip}' \
  /var/log/nginx/access.log | sort -rn | head -20

Дальше — распределение трафика по типам файлов, чтобы понять, что именно качают: HTML-страницы (легитимные посетители) или медиа/архивы (подозрительно, если доля резко выросла).

awk '{n=split($7,a,"."); ext=a[n]; sum[ext]+=$10} END {for (e in sum) print sum[e]/1024/1024" MB", e}' \
  /var/log/nginx/access.log | sort -rn | head -15

Ключевой шаг — referrer. Если конкретный файл массово запрашивают с одного и того же чужого домена — это хотлинк, а не органика.

grep "GET /uploads/" access.log | \
  awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -20

Если в топе видите - (пустой referrer) вперемешку с одним и тем же User-Agent и равномерным интервалом между запросами — похоже на бота, который обходит каталог напрямую по URL, а не переходит по ссылкам с сайта.

awk '{print $12, $13}' access.log | sort | uniq -c | sort -rn | head -20

Для регулярного разбора удобнее не гонять awk руками, а поднять GoAccess или Grafana Loki с дашбордом по referrer/UA/типу файла — тогда всплеск видно сразу на графике, а не только постфактум в счёте. Подробнее о самом чтении логов и извлечении сигнала из шума — в статье про то, что видно в access-логе при атаке: методика разбора та же, меняется только то, что вы ищете.

Отдельно проверьте, не относится ли рост к собственным ошибкам конфигурации, а не к внешним потребителям — отключённый кеш, gzip не туда, случайно открытый бэкап в веб-корне тоже раздувают исходящий трафик, и это разбирается отдельно в статье про то, как накручивается плата за исходящий трафик. Если логи показывают, что трафик размазан по вашим же путям без аномального referrer — вам туда, а не в защиту от хотлинков.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Хотлинк: ваш сервер работает бесплатным CDN для чужого сайта

Признак в логах однозначный: один и тот же файл (обычно картинка, реже видео или PDF) запрашивается тысячами хитов с уникальных IP, но referrer у всех один и тот же чужой домен, не ваш. Часто это:

  • форум или доска объявлений, где пользователи вставили [img]https://ваш-домен/photo.jpg[/img];
  • маркетплейс, зеркалирующий чужие карточки товаров вместе с прямыми ссылками на изображения;
  • новостной агрегатор или Telegram-канал с автопарсингом статей, который не перезаливает картинки к себе, а тянет их с оригинала при каждом открытии.

Экономика простая: показ картинки на чужой странице с посещаемостью в разы больше вашей — это ваш трафик и ваши деньги на каждый просмотр их страницы. При статичном прайсе за гигабайт рост в разы за неделю — типичный след внезапно завирусившегося чужого поста с вашей картинкой внутри.

Отличить хотлинк от обычного шаринга ссылки просто: при шаринге ссылки на вашу страницу referrer будет вести на HTML, который посетитель открыл, а сама страница подгрузит с вашего же домена. При хотлинке чужая страница напрямую ссылается на файл в теге <img>/<video>, ваш HTML вообще не запрашивается — в логах будет много хитов к /uploads/*.jpg и почти нет к соответствующим .html.

Утечка прямых ссылок на закрытый контент

Здесь сценарий тоньше: контент не должен быть публичным вообще, но у вас нет ничего, кроме «непредсказуемого» URL, что мешало бы его раздать. Если ссылка вида https://домен/files/report-2026.pdf один раз попала в публичный Telegram-канал, форум или была проиндексирована поисковиком (да, и такое бывает с прямыми ссылками без noindex на файл), она разойдётся сама.

Как найти: ищите в логах один и тот же путь к файлу за закрытым контуром (не связанный с обычным пользовательским флоу) с резко возросшим числом хитов и referrer, ведущим на внешние площадки, где вы такую ссылку никогда не публиковали.

grep "/files/report-2026.pdf" access.log | \
  awk -F'"' '{print $4}' | grep -v "^-$\|ваш-домен" | sort | uniq -c | sort -rn

Проблема утечки прямой ссылки в том, что её нельзя «отозвать» — она либо работает для всех, либо не работает ни для кого, пока вы не поменяете URL целиком. А после смены URL легитимные пользователи, у которых ссылка была в закладках или письме, тоже её потеряют. Правильное решение — не полагаться на секретность самого пути, а выдавать временные подписанные ссылки под каждого пользователя или сессию (об этом — ниже).

Боты-скрейперы: обходят каталог, игнорируют robots.txt

Отличительная черта ботов-парсеров — предсказуемость. Запросы идут по возрастающим или последовательным ID (/product/1001.jpg, /product/1002.jpg...), с одинаковым интервалом между хитами, часто ночью, когда обычные посетители спят. User-Agent либо честно называет себя (python-requests, Scrapy, okhttp, конкретный краулер), либо маскируется под браузер, но выдаёт себя отсутствием сопутствующих запросов к CSS/JS/шрифтам — реальный браузер их всегда подгружает вместе со страницей, скрипт — нет.

# IP, которые качают только медиа/архивы и ни разу не запросили .css/.js
awk '$7 !~ /\.(css|js)$/ {ip[$1]++} $7 ~ /\.(css|js)$/ {css[$1]++}
     END {for (i in ip) if (!(i in css)) print ip[i], i}' access.log | sort -rn | head -20

robots.txt — это просьба, а не барьер: он останавливает только добросовестных ботов (обычные поисковики, известные SEO-инструменты). Скрейпер, написанный конкретно под вашу площадку, его прочитает и проигнорирует. Поэтому для агрессивных парсеров нужна не декларация, а техническое ограничение — rate limiting и, при необходимости, блокировка по IP/подсети или User-Agent (с осторожностью: подмена UA — первое, что делает скрейпер в ответ на такую блокировку).

Отдельная категория последних лет — краулеры LLM-провайдеров, которые обходят сайты для обучающих датасетов. Они обычно представляются честно (характерный User-Agent), но могут генерировать заметную нагрузку на медиатяжёлые разделы. Решение то же: rate limiting per-UA плюс robots.txt с явным Disallow для конкретных ботов — часть из них его всё же соблюдает.

Защита: проверка Referer, ограничение скорости и подписанные ссылки

Для хотлинка стандартное решение — проверка заголовка Referer на уровне nginx: если запрос на изображение пришёл не с вашего домена и не пустой (прямой переход, закладка) — отдаём заглушку или 403 вместо оригинала.

location ~* \.(jpe?g|png|gif|webp|mp4)$ {
    valid_referers none blocked ваш-домен.ru *.ваш-домен.ru;
    if ($invalid_referer) {
        return 403;
        # или подмена на заглушку:
        # rewrite ^ /images/hotlink-placeholder.jpg last;
    }
}

none разрешает запросы без referer (прямые ссылки, некоторые почтовые клиенты и мессенджеры их не передают), blocked — запросы, где referer вырезан прокси или браузером из соображений приватности. Без этих двух пунктов вы отрежете часть легитимных пользователей — учитывайте это перед тем, как ставить return 403 вместо мягкой заглушки.

Второй рубеж — ограничение скорости отдачи per-connection, которое не блокирует, а просто не даёт одному источнику выжрать всю полосу:

location /uploads/ {
    limit_rate_after 10m;   # первые 10 МБ без ограничения — не мешаем обычной загрузке
    limit_rate 512k;        # дальше — не быстрее 512 КБ/с на соединение
}

Вместе с этим — limit_req/limit_conn по IP, чтобы один клиент не открывал сотни параллельных скачиваний. Механику самого алгоритма и типичные ошибки настройки (слишком жёсткий burst, отсутствие nodelay) разбирает статья как работает rate limiting — она пригодится, чтобы не заблокировать заодно и реальных посетителей за пачку параллельных запросов картинок на одной странице.

Третий, самый надёжный вариант — не полагаться на секретность URL и не гонять список referrer-ов, а выдавать подписанные ссылки с ограниченным временем жизни. В nginx это модуль ngx_http_secure_link_module (собран по умолчанию в большинстве дистрибутивов nginx):

location /secure/ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri секретная-строка";

    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }  # ссылка истекла

    root /var/www/private;
}

Ссылка генерируется на бэкенде под конкретного пользователя и запрос с временной меткой истечения, например на час или сутки:

import hashlib, base64, time

def signed_url(path, secret, ttl=3600):
    expires = int(time.time()) + ttl
    raw = f"{expires}{path} {secret}".encode()
    md5 = base64.urlsafe_b64encode(hashlib.md5(raw).digest()).decode().rstrip("=")
    return f"{path}?md5={md5}&expires={expires}"

Если файлы отдаются через S3-совместимое хранилище — там та же идея работает через presigned URL с TTL из коробки, без ручной генерации подписи. Плюс подхода: даже если ссылка утечёт в паблик, она сама перестанет работать через заданное время — не нужно менять URL для всех пользователей разом, как при утечке статичной прямой ссылки.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Хотлинк-защита не сломает соцсети и мессенджеры, которые тоже подгружают превью картинок?

Может. Telegram, WhatsApp и подобные сервисы делают серверный запрос за превью без человеческого referer — с valid_referers none blocked они обычно проходят, но стоит явно протестировать конкретные площадки, которые вам важны, прежде чем включать return 403 на проде.

Достаточно ли скрыть путь к файлу (случайное имя вместо /uploads/1.jpg), чтобы не защищать отдельно?

Нет — случайное имя защищает от перебора, но не от утечки конкретной ссылки: если её один раз кто-то опубликовал, случайность имени уже не помогает. Для закрытого контента нужна подпись с истечением, а не просто «неугадываемый» URL.

Rate limiting по IP не заблокирует пользователей за NAT или мобильного оператора, где сотни человек выходят с одного IP?

Заблокирует лишних, если лимит выставлен слишком жёстко. Начинайте с мягкого лимита (например, limit_req zone=... burst=20 nodelay) и смотрите долю 429/503 в логах после включения — если она заметна на легитимном трафике, поднимайте порог.

Как быстро понять, что рост — это хотлинк, а не просто вирусный успех статьи?

Смотрите долю запросов к HTML-страницам относительно запросов к медиафайлам с того же referrer. При вирусном успехе HTML и картинки растут пропорционально: люди читают страницу целиком. При хотлинке HTML почти не растёт, а конкретный медиафайл — в разы.

Можно ли одновременно использовать проверку Referer и подписанные ссылки?

Да, и для закрытого контента это разумно: подпись с истечением — основной барьер, а проверка referer — дополнительный слой, который отсекает часть автоматических ботов, даже не пытающихся генерировать корректную подпись.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →