Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

Linux: EADDRINUSE (address already in use) — как быстро найти и освободить занятый порт

EADDRINUSE (address already in use) возникает, когда приложение не может выполнить bind() на IP:порт. Ниже — быстрый алгоритм: определить точный адрес бинда, найти слушателя через ss/lsof/fuser, проверить systemd socket-activation, IPv6 и TIME_WAIT, затем освободить порт безопасно.
Linux: EADDRINUSE (address already in use) — как быстро найти и освободить занятый порт

Ошибка EADDRINUSE (она же address already in use, port already in use) означает простую вещь: процесс пытается сделать bind() на IP:порт, которые ядро уже считает занятыми. На сервере это чаще всего всплывает при рестарте веб-сервиса, деплое, смене конфигурации, поднятии второго экземпляра приложения или при конфликте с systemd socket-юнитом.

Ниже — практический разбор причин и пошаговый алгоритм диагностики на Linux: без «магии», но с теми командами, которые реально помогают на проде.

Что именно «занято»: порт, адрес или сочетание?

Конфликт бывает не только «порт занят», а именно «занята конкретная комбинация адреса и порта». Поэтому первым делом зафиксируйте, на какой адрес пыталось забиндиться приложение (это обычно видно в логе или конфиге).

  • 0.0.0.0:PORT — слушаем все IPv4-адреса. Такой биндинг конфликтует почти с любым слушателем на этом же порту в IPv4.

  • 127.0.0.1:PORT — слушаем только loopback. Может не конфликтовать с процессом на 1.2.3.4:PORT, но будет конфликтовать с 0.0.0.0:PORT.

  • [::]:PORT — IPv6. На многих системах IPv6-сокет может принимать и IPv4 (v4-mapped), и тогда «внезапно» мешает именно IPv6-листенер.

Самый быстрый путь к решению: сравнить точную пару IP:порт из ошибки/конфига с тем, что реально слушает система.

Быстрый чеклист: кто слушает порт прямо сейчас

Начинайте с ss: он быстрый и почти всегда показывает нужную связку «порт → процесс».

1) ss: найти LISTEN и PID

ss -lntp
ss -lntp '( sport = :80 )'
ss -lntup '( sport = :53 )'

Коротко по ключам:

  • -l — только слушающие сокеты, -n — без DNS-резолва, -t/-u — TCP/UDP, -p — показать процесс.

  • Если PID не виден, обычно не хватает прав (запускайте от root) или сокет находится в другом network namespace (контейнеры).

2) lsof: альтернативный способ (иногда лучше показывает детали)

lsof -nP -iTCP:80 -sTCP:LISTEN
lsof -nP -iUDP:53

lsof удобен, когда нужно увидеть пользователя, аргументы процесса, рабочий каталог. Но на нагруженных хостах он может быть ощутимо тяжелее, чем ss.

3) fuser: «кто держит порт» и быстрый килл (осторожно)

fuser -v 80/tcp
fuser -v 53/udp

Если вы точно понимаете, что это «лишний» процесс, его можно завершить. Но на продакшене чаще правильнее сначала остановить сервис штатно (systemd/supervisor/оркестратор), и только затем добивать остатки.

fuser -k 80/tcp

Вывод ss и lsof с PID процесса, который слушает занятый порт

Если LISTEN нет, а EADDRINUSE есть: TIME_WAIT, namespace и другие «невидимые» причины

Сценарий, который часто сбивает с толку: сервис падает с EADDRINUSE, а ss -lntp не показывает слушателя. На практике причины обычно такие:

  • порт занят не в вашем network namespace (контейнер, отдельный namespace, chroot сам по себе не влияет);

  • конфликт возникает не на уровне LISTEN, а из‑за переиспользования конкретных локальных адресов/портов (включая ситуации с TIME_WAIT);

  • порт держит systemd через socket-activation.

TIME_WAIT: что это и почему иногда «мешает»

TIME_WAIT — нормальное состояние TCP после закрытия соединения: оно защищает от путаницы со «старыми» пакетами. В типичном веб-сценарии большое число TIME_WAIT — это чаще симптом паттерна соединений (много коротких коннектов), а не «поломка».

Важно: TIME_WAIT сам по себе обычно не мешает поднять LISTEN на том же порту. Если мешает, значит приложение делает что-то нестандартное: пытается повторно использовать конкретные локальные порты/адреса в исходящих соединениях, использует фиксированный source-port, поднимает много краткоживущих сокетов в одном процессе и т. п.

Быстро посмотреть картину по состояниям:

ss -tan state time-wait | head
ss -tan | awk '{print $1}' | sort | uniq -c | sort -nr | head
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

systemd socket-activation: порт слушает systemd, а не ваш сервис

На современных дистрибутивах частая ловушка: включен socket-юнит, и именно он держит порт, а ваш демон при старте пытается слушать этот порт сам. В результате — EADDRINUSE, и «виновник» выглядит как что-то постороннее.

Как проверить, не слушает ли порт socket-юнит

systemctl list-sockets
systemctl list-sockets | grep -E '(:80|:443|:3000|:8080)'

Если нашли подходящий socket, посмотрите его привязку и юнит:

systemctl status nginx.socket
systemctl cat nginx.socket

Типовые решения:

  • если socket-активация не нужна — отключить .socket и включить обычный .service;

  • если socket-активация нужна — убедиться, что сервис умеет принимать уже открытый дескриптор и не делает bind() сам.

Пример отключения socket-юнита:

systemctl disable --now nginx.socket
systemctl enable --now nginx.service

Если вы управляете несколькими воркерами/демонами через supervisor/systemd, полезно держать под рукой разбор типичных конфликтов запусков: очереди, supervisor и systemd для воркеров.

SO_REUSEPORT и SO_REUSEADDR: когда «можно делить порт», а когда нельзя

В обсуждениях EADDRINUSE часто всплывают SO_REUSEADDR и SO_REUSEPORT. Это не «волшебные флаги», а инструменты под конкретные сценарии.

SO_REUSEADDR: быстрый рестарт и особые случаи

SO_REUSEADDR обычно помогает корректнее переживать перезапуски и переходные состояния сокетов, но не позволяет двум произвольным процессам одновременно слушать один и тот же TCP-порт на одном и том же адресе.

Для UDP поведение отличается: там совместное использование порта встречается чаще, и из-за этого диагностика «почему пакеты прилетают не туда» может быть сложнее.

SO_REUSEPORT: несколько слушателей на одном порту

SO_REUSEPORT позволяет нескольким сокетам слушать одну и ту же пару адрес:порт, а ядро распределяет входящие соединения между ними. Это полезно для высоконагруженных сервисов и некоторых моделей масштабирования.

Но учитывайте условия:

  • все процессы должны явно включить SO_REUSEPORT;

  • не все серверы и фреймворки корректно поддерживают этот режим «из коробки»;

  • ошибка настройки может привести к неожиданной маршрутизации трафика и гонкам в логике приложения.

Если задача — поднять один сервис на одном порту, лечить EADDRINUSE через SO_REUSEPORT почти всегда плохая идея. Сначала устраните реальный конфликт.

Типовые причины EADDRINUSE на серверах и как их быстро подтвердить

Причина 1: старый экземпляр сервиса не умер

Сервис рестартовали, но дочерний процесс остался жить; менеджер поднял второй экземпляр; сокет удерживает воркер, который не завершился.

Проверка:

ss -lntp '( sport = :8080 )'
ps -fp PID

Решение: штатная остановка через init-систему/менеджер процессов, затем контроль, что LISTEN исчез.

Причина 2: конфликт конфигурации (два сервиса слушают один порт)

Например, Nginx и Apache одновременно настроены на 0.0.0.0:80; или два инстанса приложения слушают 127.0.0.1:3000.

Подтверждение — ss/lsof. Дальше вы выбираете «кто главный»: меняете порт, адрес бинда или отключаете лишний сервис.

Причина 3: сервис слушает на IPv6 и «перехватывает» IPv4

Вы запускаете процесс на 0.0.0.0:80, а в системе уже есть LISTEN на [::]:80, и ядро настроено так, что IPv6-сокет принимает также IPv4. В логах это выглядит как «порт занят», хотя адрес «другой».

Проверка:

ss -lntp | grep ':80'

Решение зависит от стека: либо разводите сервисы по разным адресам, либо аккуратно разделяете IPv4/IPv6 поведение на уровне приложения/ОС (важно не сломать доступность).

Причина 4: порт занят в другом network namespace (контейнеры)

В Docker/Podman/Kubernetes встречаются две противоположные ситуации:

  • на хосте порт свободен, но внутри контейнера этот порт уже занят (конфликт внутри namespace контейнера);

  • в контейнере порт свободен, но публикация порта на хосте конфликтует с хостовым слушателем.

Проверяйте обе стороны: хост и конкретный контейнер (внутри него — ss/lsof).

Как действовать безопасно: «освободить порт» без лишнего даунтайма

Когда виновник найден, не начинайте с kill -9. На продакшене лучше идти по ступеням:

  1. Остановить сервис штатно (systemd, supervisor, контейнер-оркестратор).

  2. Проверить, что LISTEN исчез: ss -lntp по нужному порту.

  3. Если не исчез — выяснить процесс через lsof/fuser и завершить корректно.

  4. Если процесс завис: сначала TERM, затем KILL.

Если сервис крутится на сервере и важно быстро масштабироваться или изолировать окружения, часто удобнее вынести проблемный компонент на отдельный VDS, чтобы порты/юниты/зависимости не конфликтовали между проектами.

Проверка systemd socket-activation: list-sockets показывает юнит, удерживающий порт

Профилактика: как сделать так, чтобы EADDRINUSE не возвращался

1) Явно фиксируйте адрес бинда и порт

Не полагайтесь на «по умолчанию слушаем всё». Явно задавайте: 127.0.0.1 для внутреннего бекенда, публичный IP для фронта, отдельные порты для разных сред.

2) Проверьте, не включен ли лишний socket-юнит

Для systemd держите в голове, что .socket и .service могут жить параллельно и конфликтовать, особенно после установки пакетов, где socket-activation включается автоматически.

3) Делайте корректный graceful-restart

Многие демоны умеют «мягкую» перезагрузку без потери слушающего сокета (мастер держит порт, воркеры заменяются). Если вместо этого делать жесткий рестарт, вероятность поймать проблемы на стыке выше.

4) Не лечите симптомы sysctl-настройками без понимания

При большом числе TIME_WAIT часто хочется «подкрутить сеть». Иногда это оправдано, но обычно лучше сначала понять причину (паттерн соединений, keepalive, балансировщик, короткие запросы, тестовые нагрузки) и только потом менять параметры, чтобы не ухудшить стабильность.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Мини-шпаргалка команд

Если нужно «в один экран»:

ss -lntp '( sport = :PORT )'
ss -lntup '( sport = :PORT )'
lsof -nP -iTCP:PORT -sTCP:LISTEN
fuser -v PORT/tcp
systemctl list-sockets
ss -tan state time-wait | head

Заключение

EADDRINUSE почти всегда решается предсказуемо: выясняете точный IP:порт, находите слушателя (или socket-юнит), учитываете IPv4/IPv6 и контейнерные namespace, после чего освобождаете порт штатно. А если регулярно видите «LISTEN нет, но порт занят» — отдельно проверьте socket-activation и сценарии, где приложение переиспользует локальные порты на фоне большого числа TIME_WAIT.

Если хотите, можно быстро докопаться до конкретного кейса: пришлите строку ошибки из лога и вывод ss -lntp по проблемному порту.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...