Плата за исходящий трафик: как её незаметно накрутить
Провайдер прислал счёт за трафик, который вдвое-втрое больше обычного, а вы ничего не меняли в коде и не запускали новых фич. Знакомая ситуация: почти всегда виноват не рост аудитории, а рутинная техническая недоработка, которая годами раздаёт лишние байты — просто раньше это было незаметно. Разберём пять типовых мест утечки и как их найти у себя за 10 минут.
Содержание
- Почему это вообще больно
- Сценарий 1: нет сжатия ответов сервера
- Сценарий 2: клиент не кеширует статику — файлы качаются заново
- Сценарий 3: изображения и видео в оригинальном весе
- Сценарий 4: публичный эндпоинт раздаёт бэкап или большой файл всем подряд
- Сценарий 5: репликация и бэкапы идут через дорогой канал вместо локального
- Чек-лист: где искать лишний трафик у себя
Почему это вообще больно
На VPS с щедрым или безлимитным трафиком (как большинство современных тарифов) перерасход просто незаметен — сервер отдаёт условные 50 ГБ вместо нужных 15, и никто не считает разницу. А вот у провайдеров с потарифной оплатой исходящего трафика (объектные хранилища, CDN, часть облачных площадок, трафик между регионами у больших облаков) каждый лишний гигабайт — это строчка в счёте. Проблема в том, что причины раздувания одни и те же независимо от модели оплаты — просто в одном случае они бьют по деньгам сразу, а в другом копятся незаметно и всплывают, когда вы решите перенести часть инфраструктуры на тарифный сервис или подключить CDN с оплатой за трафик.
Дальше — пять конкретных сценариев, из-за которых трафик раздувается в разы, и как проверить каждый у себя.
Сценарий 1: нет сжатия ответов сервера
Если nginx или ваше приложение отдают HTML, CSS, JS, JSON без gzip/brotli — вы гоняете в 3-10 раз больше байт, чем нужно. Текстовые форматы сжимаются отлично: страница в 200 КБ без сжатия превращается в 30-40 КБ с gzip и ещё меньше с brotli.
Проверка — одна команда:
curl -s -o /dev/null -w '%{size_download}\n' -H 'Accept-Encoding: gzip' https://example.com/
curl -s -o /dev/null -w '%{size_download}\n' https://example.com/
Если числа совпадают — сжатие не работает, хотя заголовок был отправлен. Проверьте, что реально пришло:
curl -sI -H 'Accept-Encoding: gzip, br' https://example.com/ | grep -i content-encoding
Пусто в ответе — сжатие выключено или настроено криво (частая ошибка — gzip включён глобально, но gzip_types не перечисляет нужный MIME-тип, и JSON/SVG уходят как есть). Минимальный рабочий конфиг nginx:
gzip on;
gzip_vary on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml application/xml+rss text/javascript
image/svg+xml;
Brotli даёт дополнительные 10-20% к gzip на текстовых форматах, но требует модуля (ngx_brotli, собирается отдельно или ставится из репозитория дистрибутива):
brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css application/json application/javascript
text/xml application/xml image/svg+xml;
Отдельная ловушка: сжатие уже упакованных форматов (JPEG, MP4, ZIP, WOFF2) бесполезно и только тратит CPU — не добавляйте их в gzip_types/brotli_types, они и так плотные.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSСценарий 2: клиент не кеширует статику — файлы качаются заново
Если у CSS/JS/шрифтов/картинок нет заголовков кеширования или стоит Cache-Control: no-cache там, где это не нужно, браузер каждого посетителя перекачивает одни и те же файлы при каждом визите и даже при переходе между страницами сайта. Для сайта с постоянной аудиторией это легко удваивает трафик статики.
Проверка:
curl -sI https://example.com/assets/app.css | grep -iE 'cache-control|expires|etag'
Если заголовков нет вообще — браузер полагается на эвристику самого браузера, что непредсказуемо. Правильная схема — версионировать файлы (хэш в имени: app.a1b2c3.css) и ставить долгий кеш на неизменяемые ассеты:
location ~* \.(css|js|woff2?|svg|png|jpe?g|webp|avif)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location = /index.html {
add_header Cache-Control "no-cache";
}
Ключевая идея: HTML — короткий кеш или no-cache (он лёгкий и должен обновляться), а версионированная статика — год и immutable, потому что при изменении файла меняется и его имя, повторной загрузки при обновлении не потребуется. Если версионирования нет и имена файлов постоянные, ставьте кеш короче (часы, не год), иначе пользователи будут видеть старую статику после деплоя.
Отдельно проверьте ETag/If-None-Match — на статике без версионирования это хоть какая-то защита от полной перекачки при повторном визите:
curl -sI https://example.com/logo.png | grep -i etag
Сценарий 3: изображения и видео в оригинальном весе
Самый частый источник лишнего трафика на контентных и e-commerce сайтах: в CMS или на диске лежит оригинал с камеры или из фотостока (4-8 МБ на изображение, необработанное видео), а на страницу он отдаётся как есть, без адаптации под веб.
Быстрая ревизия каталога:
find /var/www/example.com/uploads -type f \( -iname '*.jpg' -o -iname '*.png' \) -size +500k \
-exec ls -lh {} \; | sort -k5 -h -r | head -20
Это покажет самые тяжёлые файлы, которые реально отдаются посетителям. Дальше — три независимых шага:
- Пересжать существующее. Для JPEG/PNG —
jpegoptim,optipng,pngquant; для конвертации в современные форматы —cwebp/avifenc. Пример пакетного пересжатия:
find . -iname '*.jpg' -exec jpegoptim --max=80 --strip-all {} \;
- Отдавать правильный размер, а не оригинал. Картинка 4000×3000 для блока шириной 400px в вёрстке — чистый перерасход в десятки раз. Нужны отресайженные варианты под
srcsetили imgproxy/thumbnail-сервис на лету. - Проверить видео отдельно. Необработанное видео с телефона или экрана — это битрейт, рассчитанный не под веб-стриминг. Перекодировка через ffmpeg с разумным битрейтом обычно уменьшает файл в разы без заметной потери качества:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow -c:a aac -b:a 128k output.mp4
Ориентир (именно ориентир, у вас цифры будут другими в зависимости от контента): переход с оригиналов на оптимизированные веб-форматы обычно сокращает вес медиа в 2-5 раз. Точную экономию у себя вы увидите только измерив: посчитайте суммарный вес каталога uploads до и после через du -sh.
Сценарий 4: публичный эндпоинт раздаёт бэкап или большой файл всем подряд
Отдельная и более болезненная категория: не постепенное раздувание, а разовая утечка большого объёма — забытый публичный доступ к дампу базы, архиву бэкапа или директории с логами, которую кто-то (бот, сканер, поисковый краулер) методично скачивает.
Типичные места, где это всплывает:
- бакет объектного хранилища с публичным ACL, где лежат бэкапы;
/backup/,/dump.sql,/wp-content/uploads/backup-*.zip— доступны напрямую по URL без авторизации;- директория со статическими файлами, где
autoindex onв nginx показывает листинг каталога с бэкапами внутри.
Проверка листинга и прямого доступа:
curl -s https://example.com/backup/ | grep -i 'index of'
curl -sI https://example.com/backup/dump.sql.gz
Если возвращается 200 OK и реальный размер файла — это открытый эндпоинт, и сканеры интернета найдут его без вашего участия за считаные дни. Смотрите логи на предмет повторяющихся скачиваний одного и того же тяжёлого файла:
awk '{print $7, $10}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
Первая колонка — сколько раз запрашивался URL, вторая — размер ответа. Один URL с большим размером и сотнями обращений — характерный след утечки.
Что делать:
- закрыть
autoindex(autoindex off;в nginx, это должно быть по умолчанию, но панели управления иногда включают его сами); - убрать бэкапы из веб-корня — им там вообще не место, хранить отдельно от
document rootс ограничением доступа по IP или авторизацией; - на объектных хранилищах — явно проверить ACL бакета, публичный доступ должен быть осознанным исключением, а не дефолтом;
- добавить
robots.txtс запретом индексации служебных путей — это не защита от целенаправленной атаки, но снижает случайный трафик от легитимных краулеров.
Сценарий 5: репликация и бэкапы идут через дорогой канал вместо локального
Если бэкапы или репликация базы уходят в другой регион или к другому провайдеру напрямую через публичный интернет, вы платите за межрегиональный/межконтинентальный исходящий трафик там, где могло бы быть либо дёшево (внутри одного дата-центра/региона), либо вообще бесплатно (через приватную сеть провайдера).
Проверить, куда реально идёт трафик, можно через vnstat или iftop, глядя на адресата:
vnstat -i eth0 --json | jq '.interfaces[0].traffic'
iftop -i eth0 -P
И сверить IP назначения с тем, в каком регионе физически стоит адресат бэкапа/реплики. Частые причины дорогого пути:
- бэкап настроен на S3-совместимое хранилище в другом континенте, хотя рядом с сервером есть локальное или хотя бы внутрирегиональное хранилище;
- репликация БД идёт напрямую между серверами разных провайдеров вместо промежуточного сжатия или через VPN-туннель с меньшим числом ретрансляций;
- нет сжатия самого бэкапа перед отправкой (
pg_dump | gzipвместоpg_dumpв чистом виде — экономия обычно кратная для текстовых дампов SQL).
Практические шаги:
# сжатие дампа перед отправкой куда угодно
pg_dump mydb | gzip -9 > mydb_$(date +%F).sql.gz
# rclone с ограничением полосы, чтобы не забить канал и контролировать объём
rclone sync /backups remote:bucket --bwlimit 10M --transfers 4
Если провайдер бэкап-хранилища и провайдер основного сервера разные — посчитайте, что дешевле: держать хранилище рядом (тот же регион, часто внутренний трафик между сервисами одного провайдера не тарифицируется или стоит на порядок дешевле) или платить за трансконтинентальный исходящий каждую ночь. Для реплик PostgreSQL и подобных систем разница особенно заметна — это непрерывный поток, а не разовая передача, и он копится сутками.
Чек-лист: где искать лишний трафик у себя
Пройдитесь по пунктам за один присест — большинство проверок занимают пару минут:
| Проверка | Команда | Что ищем | |||
|---|---|---|---|---|---|
| Сжатие ответов | `curl -sI -H 'Accept-Encoding: gzip,br' URL \ | grep -i content-encoding` | Пустой ответ = сжатие не работает | ||
| Кеш статики | `curl -sI URL/app.css \ | grep -i cache-control` | Нет заголовка или no-cache на неизменяемых файлах | ||
| Тяжёлые изображения | find uploads -size +500k | Оригиналы без адаптации под веб | |||
| Открытый листинг | `curl -s URL/backup/ \ | grep -i 'index of'` | autoindex on на служебных путях | ||
| Топ по трафику в логах | `awk '{print $7,$10}' access.log \ | sort \ | uniq -c \ | sort -rn` | Один URL с большим весом и частыми обращениями |
| Куда уходит трафик | vnstat/iftop | Межрегиональный адресат для бэкапов/реплики | |||
| Вес дампа до отправки | du -sh dump.sql* | Сжимаете ли вы бэкап перед отправкой |
Если считаете суммарный трафик отдельно по сервисам, полезно заранее прикинуть порядок цифр — общий разбор того, из чего складывается цена гигабайта трафика, поможет понять, где экономия действительно окупает время на настройку, а где не критично.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
С чего начать, если времени мало и нужно быстро сократить счёт?
С проверки сжатия (сценарий 1) и открытых эндпоинтов (сценарий 4) — первое чинится одной строкой в конфиге nginx и сразу даёт эффект на всём трафике, второе может останавливать разовую, но крупную утечку.
Насколько сильно gzip/brotli реально экономят трафик?
Зависит от типа контента: текстовые форматы (HTML, CSS, JS, JSON, SVG) сжимаются заметно, обычно в несколько раз; уже сжатые форматы (JPEG, MP4, WOFF2, ZIP) — почти не сжимаются повторно, включать для них gzip бессмысленно и тратит CPU впустую.
Если VPS с безлимитным трафиком — вообще не нужно этим заниматься?
Разгрузка сервера всё равно снижает нагрузку на CPU/диск и ускоряет отдачу для пользователей, но да, финансовой мотивации меньше. Стоит держать в порядке на случай, если часть инфраструктуры позже переедет на тарифный сервис (CDN, объектное хранилище, другой регион).
Как понять, что проблема именно в трафике, а не в чём-то другом, если трафик резко упал или пропал после переезда?
Это отдельная история — там чаще виноваты DNS, маршрутизация или неверно перенесённые правила firewall, а не перерасход. Сначала сверьте объём запросов в логах до и после переезда, а не только байты.
Автоматизация проверок — есть смысл ставить мониторинг?
Да, если объём трафика заметен в бюджете — простой ежедневный снимок через vnstat с алертом при аномальном скачке ловит и утечки, и разовые инциденты (DDoS, забытый краулер) быстрее, чем ручная проверка раз в месяц.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →