Когда речь про VDS заходит в плоскость расходов, «трафик» оказывается одним из самых непрозрачных пунктов. В одном месяце — тишина, в другом — скачивания обновлений, бэкапы, отладка, внезапные импорты и потоковые выгрузки. Без мониторинга и простых ограничений скорость легко уходит в сотни мегабит в секунду, а месячный объём — в сотни гигабайт. В этой статье соберём минимально необходимый набор практик и утилит: vnStat для учёта, nload для живого графика и tc для шейпинга. Плюс покажем «базовые лимиты» на уровне сервисов, чтобы не превращать ваш сервер в CDN. Если вам нужен отдельный стенд для тестов — поднимите недорогой VDS и отладьте шейпинг без влияния на прод.
О чём мы считаем и что контролируем
Прежде чем ставить инструменты, договоримся о терминах:
- Трафик — объём переданных данных, как правило, в байтах/гигабайтах (но скорость чаще в битах: Мбит/с).
- Направления: egress (исходящий) и ingress (входящий). Провайдеры тарифицируют по-разному, но следить нужно за обоими.
- PPS (packets per second) важен для сетевой нагрузки на ядро и виртуальный свитч: высокая PPS при слабом CPU убивает латентность.
- Учет по интерфейсам: для VM это обычно
eth0,ens3,ens18— смотрите выводip -br link. - 95‑й перцентиль — популярная схема биллинга в датацентрах, но большинству достаточно помесячных сумм по интерфейсу.
Цель — видеть историю, понимать текущую нагрузку и иметь «рубильник» на случай утечки или всплеска.
Инструменты: что и для чего
vnStat— лёгкий сборщик помесячной/по-дневной статистики по интерфейсу. Работает без сниффинга, берёт счетчики ядра, почти не грузит систему.nload— живой график скорости RX/TX в терминале. Удобно для оперативной диагностики.tc— ядровой инструмент управления очередями. Позволяет ограничивать скорость, задавать приоритеты, шейпить ingress черезifb.

vnStat: установка и первичная настройка
Установка
# Debian/Ubuntu
sudo apt update
sudo apt install vnstat
# RHEL/CentOS/Rocky/Alma
sudo dnf install vnstat
# Alpine
sudo apk add vnstat
После установки убедитесь, что демон запустился и знает о вашем интерфейсе:
sudo systemctl enable --now vnstat
sudo systemctl status vnstat
vnstat --iflist
Если нужного интерфейса нет в базе, добавьте его и перезапустите службу:
sudo vnstat -u -i ens18
sudo systemctl restart vnstat
База данных и ретеншн
vnStat хранит агрегированную статистику. Сразу после установки графики будут пустыми — нужен хотя бы час-другой для накопления. В конфиге /etc/vnstat.conf можно задать хранение по дням/месяцам, часовую зону и поведение при переименовании интерфейсов.
Полезные команды
# Суммарно по интерфейсу
vnstat -i ens18
# По дням
vnstat -i ens18 -d
# По часам
vnstat -i ens18 -h
# По месяцам
vnstat -i ens18 -m
# Короткий «замер секундомером» (текущая скорость за интервал)
vnstat -i ens18 -tr 5
# Непрерывный режим (почти как top)
vnstat -i ens18 -l
# JSON-вывод — удобно для автоматизации
vnstat -i ens18 --json
Практический приём: заведите еженедельную сверку трафика с бюджетом. Например, если ваш лимит 2 ТБ/месяц, то после первой недели смотрите, не ушли ли выше ~25% по vnstat -m. В случае отклонений — включайте шейпинг и проверяйте источники нагрузки. Полезно начать с харденинга базовых настроек — пригодится чек-лист из статьи Безопасность VDS: SSH и firewall.
nload: оперативный график в терминале
nload не хранит историю, зато отлично показывает «здесь и сейчас». Он полезен в момент происшествия: бьётся ли канал в потолок, симметричны ли RX/TX, какие пики и средние.
# Установка
sudo apt install nload
# Запуск по интерфейсу
nload ens18
Горячие клавиши внутри nload позволят переключать интервал усреднения и масштаб. Если интерфейсов несколько, без параметров утилита покажет список для выбора.
tc: основы шейпинга и очередей
tc работает с очередями (qdisc) на интерфейсе. Для ограничений скорости удобно использовать htb (иерархические токены) с листовой очередью fq_codel для борьбы с буферблоатом. Важно различать направления: исходящий (egress) можно ограничить прямо на интерфейсе, входящий (ingress) — через виртуальный интерфейс ifb, на который трафик перекачивается и уже там шейпится.
Ограничение исходящего (egress) через HTB
Пример: ограничим исходящий канал интерфейса ens18 до 50 Мбит/с.
#!/usr/bin/env bash
set -e
IF=ens18
RATE=50mbit
# Сброс старых очередей
sudo tc qdisc del dev "$IF" root 2>/dev/null || true
# Корневая HTB и класс
sudo tc qdisc add dev "$IF" root handle 1: htb default 10
sudo tc class add dev "$IF" parent 1: classid 1:10 htb rate "$RATE" ceil "$RATE"
# Листовая очередь fq_codel
sudo tc qdisc add dev "$IF" parent 1:10 handle 10: fq_codel
# Проверка
sudo tc -s qdisc show dev "$IF"
sudo tc -s class show dev "$IF"
Ключи rate и ceil задают гарантированную и максимальную скорость, обычно их держат равными. Единицы измерения: kbit, mbit, gbit.
Ограничение входящего (ingress) через ifb
Входящий трафик невозможно «притормозить» на реальном интерфейсе до приёма пакетов, поэтому используется ifb: пакеты перехватываются в ingress и перенаправляются в ifb0, где и шейпятся как исходящие.
#!/usr/bin/env bash
set -e
IF=ens18
IFB=ifb0
RATE=30mbit
# Модуль ifb и поднятие интерфейса
sudo modprobe ifb numifbs=1 || true
sudo ip link add "$IFB" type ifb 2>/dev/null || true
sudo ip link set dev "$IFB" up
# Сброс очередей
sudo tc qdisc del dev "$IF" ingress 2>/dev/null || true
sudo tc qdisc del dev "$IFB" root 2>/dev/null || true
# Перехват ingress и редирект в ifb
sudo tc qdisc add dev "$IF" handle ffff: ingress
sudo tc filter add dev "$IF" parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev "$IFB"
# Шейпинг на ifb
sudo tc qdisc add dev "$IFB" root handle 1: htb default 10
sudo tc class add dev "$IFB" parent 1: classid 1:10 htb rate "$RATE" ceil "$RATE"
sudo tc qdisc add dev "$IFB" parent 1:10 handle 10: fq_codel
# Проверка
sudo tc -s qdisc show dev "$IFB"
Если ядро не знает об ifb, команда modprobe ifb и параметр numifbs решат вопрос. Уточняйте имя интерфейса на вашей системе.

Шейпинг по портам/сервисам
Бывает, что нужно ограничить только определённый сервис, например загрузки по HTTP. Можно повесить фильтр по порту на класс с меньшим лимитом. Пример: не более 10 Мбит/с для TCP-порта 80 исходящего трафика.
#!/usr/bin/env bash
set -e
IF=ens18
# Базовая HTB
sudo tc qdisc del dev "$IF" root 2>/dev/null || true
sudo tc qdisc add dev "$IF" root handle 1: htb default 20
sudo tc class add dev "$IF" parent 1: classid 1:10 htb rate 10mbit ceil 10mbit
sudo tc class add dev "$IF" parent 1: classid 1:20 htb rate 100mbit ceil 100mbit
# fq_codel для листьев
sudo tc qdisc add dev "$IF" parent 1:10 handle 10: fq_codel
sudo tc qdisc add dev "$IF" parent 1:20 handle 20: fq_codel
# Фильтр u32: TCP dport 80 - в класс 1:10
sudo tc filter add dev "$IF" protocol ip parent 1: prio 1 u32 match ip sport 0 0 flowid 1:20
sudo tc filter add dev "$IF" protocol ip parent 1: prio 1 u32 match ip dport 80 0xffff flowid 1:10
# Остальное - по умолчанию в 1:20
sudo tc -s class show dev "$IF"
Для современных ядер удобно использовать фильтр flower или BPF, но u32 по-прежнему работает везде.
Проверка фактической скорости
Для теста заведите пару хостов и запустите замер. Простейший способ — поднять на одной машине сервер iperf3, на другой — клиент. Следите за nload и отчетом iperf3, чтобы убедиться, что шейпер держит потолок без больших очередей и потерь.
# На сервере
iperf3 -s
# На клиенте
iperf3 -c SERVER_IP -t 30
Как сделать шейпер постоянным после перезагрузки
Решений несколько, универсальный вариант — unit для systemd. Он гарантирует порядок запуска/остановки и логирование.
# /etc/systemd/system/tc-shaper.service
[Unit]
Description=TC shaper for ens18
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/tc-shaper up
ExecStop=/usr/local/sbin/tc-shaper down
[Install]
WantedBy=multi-user.target
# /usr/local/sbin/tc-shaper
#!/usr/bin/env bash
set -e
CMD=${1:-up}
IF=ens18
IFB=ifb0
UPRATE=50mbit
DOWNRATE=30mbit
case "$CMD" in
up)
# Egress
tc qdisc del dev "$IF" root 2>/dev/null || true
tc qdisc add dev "$IF" root handle 1: htb default 10
tc class add dev "$IF" parent 1: classid 1:10 htb rate "$UPRATE" ceil "$UPRATE"
tc qdisc add dev "$IF" parent 1:10 handle 10: fq_codel
# Ingress via ifb
modprobe ifb numifbs=1 || true
ip link add "$IFB" type ifb 2>/dev/null || true
ip link set dev "$IFB" up
tc qdisc del dev "$IF" ingress 2>/dev/null || true
tc qdisc del dev "$IFB" root 2>/dev/null || true
tc qdisc add dev "$IF" handle ffff: ingress
tc filter add dev "$IF" parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev "$IFB"
tc qdisc add dev "$IFB" root handle 1: htb default 10
tc class add dev "$IFB" parent 1: classid 1:10 htb rate "$DOWNRATE" ceil "$DOWNRATE"
tc qdisc add dev "$IFB" parent 1:10 handle 10: fq_codel
;;
down)
tc qdisc del dev "$IF" root 2>/dev/null || true
tc qdisc del dev "$IF" ingress 2>/dev/null || true
tc qdisc del dev "$IFB" root 2>/dev/null || true
ip link set dev "$IFB" down 2>/dev/null || true
ip link del "$IFB" 2>/dev/null || true
;;
*)
echo "Usage: $0 up|down"
exit 1
;;
esac
sudo chmod +x /usr/local/sbin/tc-shaper
sudo systemctl enable --now tc-shaper
Если вы используете systemd-networkd, также подойдёт скрипт ExecStartPost в unitе сети или директивы PostUp/PreDown в классических конфигурациях сети. Главное — запускать шейпер после поднятия интерфейса.
Базовые лимиты в сервисах: не всегда нужен tc
Не каждый кейс требует ядрового шейпинга. Иногда достаточно ограничить скорость на уровне HTTP‑сервера или утилит.
Nginx: ограничение скорости отдачи
Для больших файлов полезно сэкономить полосу на каждого клиента, не просаживая весь интерфейс. Пример минимальной настройки:
# http-секция
limit_rate_after 1m;
limit_rate 512k;
# location для раздачи
location /downloads/ {
# можно варьировать лимиты через map или по типам файлов
}
limit_rate_after позволяет сначала отдавать быстро первые мегабайты (ускоряет начало загрузки), а затем включать ограничение. Для лимитов по количеству запросов см. подборку пресетов: Готовые пресеты лимитов в Nginx.
rsync, wget и утилиты
Для фоновых задач часто удобнее не трогать сетевой стек, а ограничить конкретный процесс:
rsync --bwlimit=20000— ограничение примерно до 20 МБ/с.wget --limit-rate=2m— до ~2 МБ/с.
Так вы снижаете пики от бэкапов и обновлений без глобальных ограничений для всех сервисов.
Алёрты и отчёты без сложного мониторинга
Если полноценная система мониторинга ещё не развернута, выручит простая проверка бюджета через vnstat и почтовое уведомление. Идея: раз в день смотреть текущий расход месяца и прогноз.
#!/usr/bin/env bash
IF=ens18
LIMIT_GB=2000
NOW_GB=$(vnstat -m -i "$IF" | awk '/^*[0-9]+\/[0-9]+/ {print $(NF-1)}' | head -n1)
# Примерная оценка: берём среднесуточный расход и экстраполируем
DAYS_PASSED=$(date +%d | sed 's/^0*//')
AVG_PER_DAY=$(echo "scale=2; $NOW_GB / ($DAYS_PASSED)" | bc 2>/dev/null || echo 0)
DAYS_IN_MONTH=$(cal | awk 'NF {D=$NF}; END {print D}')
ESTIMATE=$(echo "scale=0; $AVG_PER_DAY * $DAYS_IN_MONTH" | bc 2>/dev/null || echo 0)
msg="iface=$IF used=${NOW_GB}GiB estimate=${ESTIMATE}GiB limit=${LIMIT_GB}GiB"
[ "$ESTIMATE" -gt "$LIMIT_GB" ] && echo "$msg" | mail -s "Traffic budget warning" root || true
Скрипт грубый, но для первых недель эксплуатации хватит. В проде лучше перейти на метрики и алёрты по порогам скорости и по накоплению трафика.
Частые проблемы и отладка
- Не тот интерфейс. В виртуалках имена меняются:
ens3,ens18,eth0. Проверяйтеip -br linkи назначайте корректный интерфейс вvnStat/tc. - ifb отсутствует. Модуль ядра не загружен — используйте
modprobe ifbи поднимайтеifb0вручную, как в примере. - Очереди накладываются. Если уже есть qdisc на интерфейсе, сначала удалите его:
tc qdisc del dev IF root, затем ставьте свой. - Единицы измерения.
mbit— мегабиты в секунду; не путайте с мегабайтами. 100mbit — это примерно 12.5 МБ/с. - Контейнеры и veth. Если шейпите конкретный контейнер, вешайте
tcна егоvethX, а не только на основной интерфейс. - «Не вижу» трафик в vnStat.
vnStatчитает системные счетчики. Если вы используете бридж/бондинг, учитывайте на каком интерфейсе растёт трафик:br0,bond0или нижележащие. - Пики при скачиваниях. Локальные лимиты в Nginx/rsync помогают сгладить всплески без глобального
tc.
Режим эксплуатации: минимальный чек-лист
- Поставить
vnStat, добавить целевой интерфейс, проверить дневные и месячные отчёты. - Держать под рукой
nloadдля онлайна. - Завести
tc-шейпер с HTB+fq_codel и ifb на базовые верхние границы egress/ingress. - Сделать автозапуск шейпера unitом systemd.
- Повесить простую проверку бюджета трафика и алёрт на превышение прогноза.
- При необходимости ограничить «тяжёлые» сервисы на уровне приложения (Nginx, rsync).
Итоги
Комбинация vnStat + nload даёт прозрачность: вы видите историю и текущую картину. tc с HTB и ifb — это надёжный способ держать канал под контролем, чтобы случайный импорт или бэкап не застрелили ваш бюджет и не ухудшили доступность сервисов. Начните с базовых верхних границ на egress/ingress, добавьте точечные ограничения для «тяжёлых» сервисов и не забывайте проверять отчёты хотя бы раз в неделю. Так вы превратите трафик из зоны риска в управляемый ресурс.


