Сообщение ядра nf_conntrack: table full, dropping packet выглядит пугающе, но обычно лечится без переустановки сервера и без магических тюнингов из интернета. На Linux VDS это одна из типичных сетевых проблем: сервисы живы, CPU и память вроде бы не уперлись в потолок, Nginx или приложение слушают порты, но новые соединения начинают отваливаться. Где-то не открывается сайт, где-то подвисают API-запросы, контейнеры Docker внезапно теряют исходящие подключения, а SSH может подключаться через раз.
Причина в том, что подсистема netfilter перестала принимать новые записи в таблицу отслеживания соединений. Эта таблица называется conntrack, а модуль ядра — nf_conntrack. Он нужен stateful-файрволу, NAT, Docker bridge-сетям, Kubernetes Service, балансировщикам и многим привычным сценариям. Когда таблица заполнена, ядро не может корректно отследить новое соединение и начинает сбрасывать пакеты. Отсюда и финальная часть сообщения: dropping packet.
Главная ошибка при такой аварии — просто поставить огромный nf_conntrack_max и забыть. Лимит надо увеличить, но сначала важно понять, кто и какими типами соединений забивает таблицу.
Что такое nf_conntrack и почему он заканчивается
nf_conntrack хранит состояние сетевых потоков: TCP-соединений, UDP-обменов, ICMP и некоторых других протоколов. Для TCP это понятнее всего: запись появляется при установлении соединения и живет до закрытия плюс некоторое время по таймаутам. Для UDP, где полноценного состояния нет, ядро все равно создает временную запись, чтобы NAT и firewall могли сопоставить ответный пакет с исходным запросом.
На обычном веб-сервере conntrack может использоваться даже тогда, когда вы не настраивали NAT вручную. Достаточно stateful-правил firewall вида «разрешить established/related», Docker с bridge-сетью, проброс портов контейнеров, локальный DNS-резолвер, прокси, VPN или большое число исходящих запросов к внешним API.
Запись в conntrack — это не бесплатная абстракция. Она занимает память ядра и место в hash-таблице. Поэтому у таблицы есть лимит nf_conntrack_max, а у hash-таблицы — размер buckets, который часто виден как hashsize или nf_conntrack_buckets. Если лимит слишком мал для вашей нагрузки или соединения слишком долго висят по таймаутам, таблица постепенно заполняется.
На Linux VDS проблема часто проявляется в нескольких сценариях. Первый — резкий всплеск входящего трафика: бот-сканеры, парсеры, легальная рекламная кампания, вебхуки или API-клиенты без keep-alive. Второй — много исходящих коротких соединений из приложения: микросервисы, очереди, интеграции с платежными и CRM-системами. Третий — Docker NAT: каждый контейнер за bridge-сетью создает дополнительные отслеживаемые NAT-состояния. Четвертый — слишком щедрые таймауты, особенно для TCP established, когда давно неактивные соединения продолжают занимать место.
Как быстро подтвердить проблему
Сначала смотрим сообщения ядра. Если таблица переполнена, обычно вы увидите строки с table full и dropping packet.
sudo dmesg -T | grep -i conntrack
sudo journalctl -k -g conntrack --since today
Типичный фрагмент выглядит так:
[Tue Jan 14 12:03:41 2026] nf_conntrack: nf_conntrack: table full, dropping packet
[Tue Jan 14 12:03:42 2026] nf_conntrack: nf_conntrack: table full, dropping packet
Теперь сравним текущее число записей с лимитом:
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
Если nf_conntrack_count близок к nf_conntrack_max, диагноз почти подтвержден. Например, 258000 записей при лимите 262144 — это уже аварийная зона. В нормальной ситуации лучше держать запас: предупреждать при 70–80%, разбираться при 85–90%, а не ждать первых dropped packet.
Для наблюдения в реальном времени удобно использовать watch:
watch -n 2 'cat /proc/sys/net/netfilter/nf_conntrack_count; cat /proc/sys/net/netfilter/nf_conntrack_max'
Если на сервере есть conntrack-tools, можно получить статистику по событиям и ошибкам:
sudo conntrack -S
Обратите внимание на counters с insert failed, drop, early_drop и похожими признаками. Названия счетчиков немного отличаются между версиями ядра и утилиты, поэтому важнее динамика: если значения растут одновременно с жалобами пользователей, conntrack участвует в инциденте.
Установка conntrack-tools
Минимальная диагностика доступна через /proc, но для нормального разбора лучше поставить утилиту conntrack. Команды отличаются только пакетным менеджером.
Debian/Ubuntu
sudo apt update
sudo apt install conntrack iproute2 procps
RHEL-based и Fedora
Для AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux и Fedora пакет обычно называется conntrack-tools.
sudo dnf install conntrack-tools iproute procps-ng
После установки проверьте, что утилита видит таблицу:
sudo conntrack -L -o extended 2>/dev/null | head
На загруженном сервере полный вывод может быть большим, поэтому не запускайте тяжелые сортировки без необходимости в самый пик аварии. Сама команда чтения таблицы тоже создает нагрузку, особенно если записей сотни тысяч или миллионы.

Кто забивает таблицу: протоколы, адреса, состояния
Следующий шаг — понять структуру записей. Если таблица забита TCP established, это одна история. Если UDP-запросами к DNS — другая. Если тысячи SYN_SENT или TIME_WAIT на один внешний адрес — третья. Начните с распределения по протоколам:
sudo conntrack -L -o extended 2>/dev/null | awk '{print $1}' | sort | uniq -c | sort -nr | head
Посмотрите, какие исходные адреса встречаются чаще всего:
sudo conntrack -L -o extended 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i ~ /^src=/) print $i}' | sort | uniq -c | sort -nr | head
И какие назначения лидируют:
sudo conntrack -L -o extended 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i ~ /^dst=/) print $i}' | sort | uniq -c | sort -nr | head
Если в топе адреса контейнерных подсетей вроде 172.17.0.0/16 или 172.18.0.0/16, почти наверняка важную роль играет Docker NAT. Если много записей на порт 53, проверьте DNS-клиентов, локальный резолвер, retry-циклы приложений и корректность upstream DNS. Если доминируют внешние клиентские IP и порт 80/443, возможно, веб-сервер получает слишком много коротких подключений или находится под нежелательной нагрузкой.
Для TCP полезно посмотреть состояния:
sudo conntrack -L -p tcp 2>/dev/null | awk '{print $4}' | sort | uniq -c | sort -nr
Здесь не надо слепо пугаться большого числа ESTABLISHED: для busy-сервера это нормально. Важна пропорция к лимиту и срок жизни записей. Подозрительными могут быть огромные хвосты TIME_WAIT, SYN_SENT, CLOSE_WAIT или масса соединений от одного приложения к одному и тому же upstream без пуллинга.
Экстренное восстановление: поднять лимит без перезагрузки
Если пользователи уже видят ошибки, а в dmesg идет conntrack table full, сначала верните запас по таблице. Временное увеличение nf_conntrack_max применяется сразу и не требует перезагрузки:
sudo sysctl -w net.netfilter.nf_conntrack_max=262144
Если у вас уже 262144 и таблица упирается в потолок, можно поднять выше:
sudo sysctl -w net.netfilter.nf_conntrack_max=524288
Не выбирайте значение наугад. У каждой записи есть стоимость в памяти ядра. На современных ядрах грубая оценка — сотни байт на запись плюс накладные расходы hash-таблицы. Лимит 524288 не означает катастрофу для сервера с несколькими гигабайтами RAM, но на маленьком VDS с 1 ГБ памяти слишком большой запас может конкурировать с приложениями, базой данных и page cache.
Практичная стартовая логика такая: для небольшого веб-сервера без контейнерной сетевой активности часто достаточно 131072–262144; для Docker-хоста, API-шлюза или сервера с активным NAT — 262144–1048576; для очень активных узлов лимит подбирают по метрикам, а не по красивым числам. После изменения смотрите не только nf_conntrack_count, но и память, latency, softirq и ошибки приложений.
Есть и радикальная команда очистки всей таблицы:
sudo conntrack -F
Используйте ее только как последний аварийный вариант. Она удалит все отслеживаемые состояния, что может оборвать активные NAT-соединения, сессии клиентов, подключения контейнеров и часть долгих запросов. Чаще безопаснее поднять лимит, найти источник и удалить только явно проблемные записи.
Например, если конкретный контейнер с адресом 172.18.0.5 создал лавину исходящих соединений, можно удалить записи по источнику:
sudo conntrack -D -s 172.18.0.5
Но и эту команду применяйте осознанно: для указанного источника соединения будут сброшены.
Постоянная настройка через sysctl
Когда авария снята, закрепите настройки в отдельном файле /etc/sysctl.d/90-conntrack.conf. Не редактируйте без нужды общий /etc/sysctl.conf: отдельный файл проще сопровождать, откатывать и переносить между серверами.
net.netfilter.nf_conntrack_max = 524288
net.netfilter.nf_conntrack_tcp_timeout_established = 86400
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 60
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 120
Примените все sysctl-файлы:
sudo sysctl --system
Значение nf_conntrack_tcp_timeout_established по умолчанию на многих системах очень большое — часто 432000 секунд, то есть пять суток. Для публичного веб-сервера это нередко избыточно. Значение 86400 секунд уже сокращает долгоживущие хвосты, но не ломает большинство нормальных сценариев. Для API-шлюзов и прокси с контролируемыми клиентами иногда используют 3600–7200, но это надо тестировать.
С UDP осторожнее. Слишком агрессивное уменьшение nf_conntrack_udp_timeout может навредить VPN, VoIP, некоторым игровым протоколам или нестандартным UDP-сервисам. Для обычной DNS-нагрузки 30 секунд часто нормально, но если таблицу забивает именно DNS-шторм, проблему лучше лечить на уровне резолвера и приложения: кэширование, исправление retry, локальный resolver, лимиты.
Hash buckets: почему одного nf_conntrack_max иногда мало
nf_conntrack_max задает максимальное число записей, но производительность поиска зависит от размера hash-таблицы. Если лимит подняли сильно, а buckets остались маленькими, цепочки в hash-таблице удлиняются. Это может увеличить CPU на сетевой обработке и ухудшить latency.
Проверьте текущие значения:
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_buckets 2>/dev/null
cat /sys/module/nf_conntrack/parameters/hashsize 2>/dev/null
Часто используют соотношение около четырех записей на bucket. Например, для nf_conntrack_max 524288 разумный hashsize — 131072. Но на VDS возможность менять hashsize зависит от ядра, способа загрузки модуля и ограничений виртуализации. Иногда параметр доступен только при загрузке модуля, иногда только через reboot, иногда не доступен в гостевой системе.
Если файл /sys/module/nf_conntrack/parameters/hashsize writable, временно изменить можно так:
echo 131072 | sudo tee /sys/module/nf_conntrack/parameters/hashsize
Для постоянной настройки при модульной загрузке создают файл /etc/modprobe.d/nf_conntrack.conf:
options nf_conntrack hashsize=131072
После этого обычно нужна перезагрузка, чтобы параметр гарантированно применился при старте. На production-сервере планируйте окно обслуживания и проверьте, что после reboot значения действительно стали ожидаемыми.
Docker NAT: частая причина переполнения conntrack
Docker сам по себе не плохой, но bridge-сеть и masquerade активно используют conntrack. Контейнер обращается наружу, пакет проходит через NAT, ядро создает запись. Контейнер принимает подключение через published port — снова участвуют правила DNAT/SNAT и state tracking. Если приложение внутри контейнера открывает тысячи коротких исходящих HTTP-запросов без connection pooling, таблица растет очень быстро.
Проверьте Docker-сети и адреса контейнеров:
docker network ls
docker ps --format 'table {{.Names}} {{.Networks}} {{.Ports}}'
docker inspect bridge --format '{{json .IPAM.Config}}'
Затем сопоставьте топ источников conntrack с подсетями Docker:
sudo conntrack -L -o extended 2>/dev/null | awk '{for (i=1; i<=NF; i++) if ($i ~ /^src=172\./) print $i}' | sort | uniq -c | sort -nr | head
В этой команде используется регулярное выражение для адресов 172.x.x.x, потому что Docker часто выдает bridge-подсети из этого диапазона. У вас могут быть другие сети: 10.x.x.x, 192.168.x.x или пользовательские CIDR из compose-файлов.
Что делать, если виноват Docker NAT? Сначала лечите приложение: включайте keep-alive, connection pool, ограничивайте параллелизм, добавляйте backoff при ошибках внешних API, кэшируйте DNS и HTTP-ответы там, где это допустимо. Затем проверьте архитектуру сети: не надо публиковать наружу лишние порты, внутренние сервисы лучше держать во внутренней Docker-сети, а наружу выводить только reverse proxy. Если отдельно разбираете правила Docker в iptables и nftables, пригодится материал про Docker firewall, iptables и nftables.
Для отдельных высоконагруженных сервисов иногда уместен network host, но это ухудшает изоляцию и требует аккуратной настройки firewall. Еще одна типичная ловушка — контейнеры с собственными DNS-ретраями. Если upstream DNS тормозит или недоступен, десятки контейнеров могут одновременно начать создавать лавину UDP-записей. В таком случае увеличение nf_conntrack_max только выиграет время, а исправление будет в DNS: локальный кэширующий резолвер, стабильные upstream, корректные таймауты и меньше агрессивных повторов.

Firewall и conntrack: не отключайте stateful-логику вслепую
Иногда при переполнении таблицы возникает соблазн отключить conntrack для части трафика через raw table или nftables notrack. Это действительно снижает нагрузку, но подходит не всегда. Если трафик проходит через NAT, notrack почти наверняка сломает обратное сопоставление пакетов. Если firewall опирается на established/related, отключение tracking приведет к неожиданным блокировкам или, наоборот, к дыркам в политике.
Notrack имеет смысл только для понятного stateless-трафика, где не нужен NAT и где правила явно учитывают отсутствие состояния. Например, для некоторых видов мониторинга или простых UDP-сервисов в специализированной схеме. Для обычного веб-хостинга, Docker-хоста и VDS с reverse proxy безопаснее сначала увеличить лимиты, настроить таймауты и устранить источник шторма.
Если у вас nftables, проверьте, не создаете ли вы лишнюю stateful-обработку там, где она не нужна. Но базовую политику established/related обычно оставляют: она защищает сервер и упрощает правила.
Как подобрать значения для небольшого и среднего VDS
Универсального значения нет, но можно идти от наблюдений. Сначала посмотрите обычный дневной пик nf_conntrack_count. Умножьте его хотя бы на два, а лучше на три, чтобы пережить всплески. Если дневной пик 60000, лимит 262144 выглядит нормально. Если пик 220000, лимит 262144 слишком тесный, лучше рассмотреть 524288 или выше и параллельно разобраться с источниками.
Не забывайте про RAM. Для VDS с 1 ГБ памяти не стоит бездумно ставить миллионы записей, особенно если там же MySQL, PHP-FPM, Redis и Docker. Для 2–4 ГБ лимиты 262144–524288 обычно выглядят разумнее, но все равно проверяйте реальное потребление памяти и OOM-события. Если текущий сервер постоянно упирается в память и сетевые лимиты, возможно, стоит подобрать более просторный облачный VDS под реальную нагрузку, а не компенсировать нехватку ресурсов рискованными настройками.
Для нагруженных NAT/прокси-узлов с 8 ГБ и выше можно планировать 1048576 и больше, если это подтверждено метриками. Отдельно проверьте лимиты приложений. Если PHP-FPM, Node.js, Java или Go-сервис открывают слишком много соединений к базе, Redis, внешним API или очередям, conntrack будет только индикатором. Настраивайте connection pool, keep-alive, таймауты клиента, circuit breaker и лимит параллелизма. У сетевой таблицы не должно быть задачи маскировать неконтролируемый fan-out приложения.
Мониторинг: чтобы не узнать о проблеме от пользователей
Минимальная проверка для cron или простого healthcheck выглядит так:
count=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
max=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
pct=$((100 * count / max))
echo $pct
В нормальном мониторинге лучше собирать обе метрики: текущее число записей и лимит. Для Prometheus node_exporter на многих системах доступны node_nf_conntrack_entries и node_nf_conntrack_entries_limit. Алерт можно строить на отношении entries к limit.
node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8
Для продакшена полезны два уровня: warning при 80% на 5–10 минут и critical при 90–95% или при росте kernel-сообщений dropping packet. Если вы используете Loki, journald forwarding или другой сборщик логов, добавьте отдельный алерт на строку nf_conntrack: table full. Если нужен простой стек метрик на одном сервере, посмотрите практику запуска VictoriaMetrics на VDS в single-node режиме.
Смотрите не только абсолютное число, но и форму графика. Плавный рост в течение дней часто указывает на долгие таймауты или утечки соединений. Резкая пила может быть следствием batch-задач, cron, очередей или контейнеров, которые периодически создают много исходящих подключений. Вертикальный скачок — повод проверить всплеск входящего трафика, деплой, ошибку ретраев или сетевую аварию у внешнего сервиса.
Чек-лист устранения conntrack table full
Если нужен короткий runbook, действуйте так:
- Подтвердите симптом через
dmesgилиjournalctl -k: ищитеnf_conntrack,table full,dropping packet. - Сравните
nf_conntrack_countиnf_conntrack_max. - Временно увеличьте
nf_conntrack_max, если таблица уперлась в лимит и сервисы уже страдают. - Установите
conntrack-toolsи посмотрите протоколы, источники, назначения и TCP-состояния. - Проверьте Docker NAT, DNS-ретраи, исходящие HTTP-клиенты, ботов и всплески входящего трафика.
- Закрепите постоянные настройки в
/etc/sysctl.d/90-conntrack.conf. - При сильном увеличении лимита проверьте
hashsizeилиnf_conntrack_buckets. - Добавьте мониторинг процента заполнения и алерт на kernel-log.
И еще важный пункт: после стабилизации обязательно вернитесь к первопричине. Если таблицу забил один контейнер из-за бесконечных ретраев к недоступному API, увеличение лимита не решит проблему качества сервиса. Если входящий трафик создает сотни тысяч коротких соединений, надо смотреть access-логи, rate limiting, keep-alive, CDN или защитные правила. Если DNS создает UDP-шторм, настраивайте резолвер и поведение клиентов.
Типичные ошибки при настройке
Первая ошибка — ставить огромный nf_conntrack_max без учета памяти. Таблица перестанет переполняться, но сервер может начать страдать от memory pressure, reclaim, swap или OOM. Вторая — уменьшать TCP/UDP таймауты слишком агрессивно. Это может породить странные обрывы долгих соединений, особенно у WebSocket, gRPC, VPN и приложений с редким обменом пакетами.
Третья ошибка — забыть про buckets. Если поднять лимит в восемь раз, а hashsize оставить маленьким, на большой нагрузке можно получить лишний CPU в сетевом стеке. Четвертая — лечить conntrack, когда реальная проблема в приложении. Например, сервис после деплоя перестал переиспользовать соединения и начал открывать новый TCP на каждый запрос к базе или API. В таблице это видно, но исправлять надо клиентские настройки.
Пятая ошибка — считать Docker единственным виновником. Да, Docker NAT часто увеличивает нагрузку на conntrack, но он может быть только усилителем. Источником может быть код приложения, DNS, очереди, внешний outage или входящий трафик. Поэтому сначала смотрим факты, затем меняем параметры.
Итог
nf_conntrack table full на Linux VDS — это не отдельная болезнь, а симптом: серверу не хватает места в таблице отслеживания соединений или кто-то создает слишком много сетевых состояний. Быстрое действие — поднять nf_conntrack_max и вернуть запас. Правильное действие — дополнительно разобрать протоколы, адреса, Docker NAT, DNS, таймауты и поведение приложений.
Хорошая рабочая конфигурация обычно состоит из трех частей: разумный лимит conntrack под реальную нагрузку, аккуратно сокращенные таймауты для лишних долгоживущих записей и мониторинг, который предупредит до первых dropping packet. Тогда таблица conntrack перестает быть скрытой точкой отказа, а сетевые инциденты становятся предсказуемыми и управляемыми.


