Выберите продукт

Debian/Ubuntu: nginx bind() to 0.0.0.0:80 failed (98: Address already in use) — как найти и устранить конфликт порта

Ошибка nginx bind() to 0.0.0.0:80 failed (98: Address already in use) в Debian/Ubuntu почти всегда означает конфликт за 80 или 443 порт. Разберём, как через ss и lsof найти виновника и безопасно освободить сокет.
Debian/Ubuntu: nginx bind() to 0.0.0.0:80 failed (98: Address already in use) — как найти и устранить конфликт порта

Ошибка nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) в Debian и Ubuntu означает простую вещь: nginx пытается открыть сокет на порту, который уже занят другим процессом или другим экземпляром самого nginx. Тот же сценарий встречается и для 0.0.0.0:443, а также для IPv6-адресов вроде [::]:80.

На практике это одна из самых частых причин, почему после изменения конфигурации, установки Certbot, запуска контейнера или включения второго веб-сервера nginx перестаёт стартовать. Сообщение выглядит тревожно из-за уровня emerg, но обычно проблема диагностируется за несколько минут.

Главное правило — не останавливать сервисы наугад. Сначала нужно понять, кто именно слушает порт. Иначе можно «починить» nginx, но случайно уронить соседний проект или внутренний прокси.

Ниже разберём типовые сценарии для конфликтов на 80 и 443: Apache, остаточные процессы nginx, Docker, systemd socket activation и ошибки в конфигурации.

Базовый принцип здесь такой: один и тот же IP:порт обычно не могут одновременно занимать два независимых процесса. Значит, если nginx не может открыть 80 или 443, этот сокет уже кем-то занят либо конфликт создан внутри его собственной конфигурации.

Как выглядит проблема и что она означает

Обычно ошибка появляется при запуске или перезапуске сервиса:

sudo systemctl restart nginx

В ответ можно увидеть примерно следующее:

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: configuration file /etc/nginx/nginx.conf test failed

Код 98 — это системная ошибка EADDRINUSE, то есть адрес уже используется. Под адресом здесь понимается связка IP и порта. Если nginx настроен слушать все IPv4-интерфейсы через 0.0.0.0:80, а порт уже занят, сервис не стартует.

Есть важная тонкость: иногда кажется, что конфликт именно внешний, хотя фактически проблема вызвана дублем внутри конфигурации nginx. Например, два server-блока пытаются слушать один и тот же IP:порт с несовместимыми параметрами. Поэтому диагностика всегда состоит из двух шагов: проверить конфиг и проверить реальные процессы, которые держат сокет.

Первый шаг: проверить конфигурацию nginx

Перед поиском «чужого» процесса убедитесь, что сам nginx не ругается на синтаксис или дубли директив. Это самый быстрый и безопасный старт:

sudo nginx -t

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

Полезно посмотреть и полный итоговый конфиг после всех include:

sudo nginx -T

Ищите все упоминания listen 80;, listen 443 ssl; и привязки к конкретным адресам. На больших конфигурациях удобнее сохранить вывод в файл и искать по нему отдельно.

sudo nginx -T > /tmp/nginx-full-config.txt
grep -R "listen 80" /etc/nginx
grep -R "listen 443" /etc/nginx

Если конфигурация выглядит корректно, переходим к главному вопросу: кто уже занял нужный порт.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Кто занял порт 80 или 443: быстрые команды диагностики

В Debian и Ubuntu удобнее всего использовать ss. Он быстро показывает TCP-сокеты в состоянии LISTEN и процессы, которым они принадлежат.

sudo ss -ltnp

Чтобы сразу отфильтровать нужные порты, выполните:

sudo ss -ltnp '( sport = :80 or sport = :443 )'

Типичный вывод может быть таким:

State  Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0      511    0.0.0.0:80      0.0.0.0:*     users:(("apache2",pid=812,fd=4),("apache2",pid=813,fd=4))
LISTEN 0      511    0.0.0.0:443     0.0.0.0:*     users:(("docker-proxy",pid=1442,fd=7))

Такой вывод сразу показывает источник конфликта: 80 занят Apache, а 443 опубликован контейнером через docker-proxy.

Второй полезный инструмент — lsof. Он особенно удобен, когда нужно быстро увидеть PID, пользователя и тип сокета.

sudo lsof -nP -iTCP:80 -sTCP:LISTEN
sudo lsof -nP -iTCP:443 -sTCP:LISTEN

Если lsof ещё не установлен, добавьте пакет:

sudo apt update
sudo apt install lsof

Практическое правило простое: сначала nginx -t, потом ss, потом lsof. Только после этого имеет смысл останавливать сервисы или править публикацию портов.

Проверка занятых портов 80 и 443 командами ss и lsof

Частый сценарий №1: конфликт Apache и nginx

Самый частый случай — на сервере уже запущен Apache. Это бывает после установки LAMP-стека, панели управления, Certbot-плагина для Apache или просто из-за старой конфигурации, о которой давно забыли.

Сначала проверьте состояние:

sudo systemctl status apache2
sudo ss -ltnp '( sport = :80 or sport = :443 )'

Если Apache действительно слушает нужные порты, придётся определить, какой веб-сервер должен быть фронтендом. На одном IP и одном порту одновременно два обычных веб-сервера работать не будут.

  • оставить только nginx;
  • оставить только Apache;
  • развести их по разным портам и использовать reverse proxy;
  • развести их по разным IP-адресам.

Если основным фронтендом должен быть nginx, остановите Apache и отключите автозапуск:

sudo systemctl stop apache2
sudo systemctl disable apache2
sudo systemctl restart nginx

Если после этого nginx запускается, причина найдена. Но перед остановкой убедитесь, что Apache действительно не нужен другому сайту или внутреннему сервису.

Если вы как раз выбираете, какой сервер использовать в роли фронтенда, может пригодиться сравнение подходов в материале nginx и Apache для современных проектов.

Иногда Apache формально установлен, но не должен стартовать сам. Тогда полезно посмотреть, кто его включил:

sudo systemctl is-enabled apache2
sudo journalctl -u apache2 -b --no-pager

Частый сценарий №2: порт занят другим экземпляром nginx

Такое тоже бывает регулярно. Например, nginx уже работает под управлением systemd, а администратор запускает его вручную. Или после неудачного перезапуска остаются процессы, которые ещё держат сокет.

Проверьте состояние сервиса и список процессов:

sudo systemctl status nginx
ps -ef | grep nginx

Если nginx уже активен, вместо start часто нужен reload или restart:

sudo systemctl reload nginx

Если сервис завис в некорректном состоянии, действуйте аккуратно:

sudo systemctl stop nginx
sudo pkill -f 'nginx: master process'
sudo pkill -f 'nginx: worker process'
sudo systemctl start nginx

После этого снова проверьте, кто слушает порт. Если сокет принадлежит только текущему экземпляру nginx, конфликт устранён.

Отдельная рекомендация для production: не смешивайте управление через systemd и ручной запуск бинарника nginx. Такой микс часто и создаёт путаницу с процессами и сокетами.

Частый сценарий №3: Docker публикует 80 или 443 наружу

Если на сервере есть контейнеры, порт вполне может быть опубликован Docker. Особенно часто это происходит после запуска образов с параметрами -p 80:80 или -p 443:443, а также в compose-файлах с секцией ports.

Сначала снова проверяем владельца сокета:

sudo ss -ltnp '( sport = :80 or sport = :443 )'

Если видите docker-proxy, посмотрите список контейнеров и их публикации:

docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Ports}}'

Нужно найти контейнер, который публикует 0.0.0.0:80->80/tcp или 0.0.0.0:443->443/tcp. Дальше вариантов обычно три:

  • остановить контейнер, если он лишний;
  • сменить публикацию порта, например на 8080:80;
  • оставить приложение за nginx и не публиковать стандартные порты наружу.

Пример остановки контейнера:

docker stop CONTAINER_ID

В compose-конфигурации правка обычно выглядит так:

ports:
  - "8080:80"

После изменения контейнеры нужно пересоздать, и только потом запускать nginx на внешних 80 и 443.

На серверах с несколькими приложениями чаще всего надёжнее держать nginx единственной точкой входа, а контейнерные сервисы слушать на внутренних портах. Если проекту нужна более гибкая сетевая схема и изоляция, удобнее размещать его на отдельном VDS, где карта портов полностью под вашим контролем.

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

Частый сценарий №4: systemd socket activation или чужой socket-unit

Более редкий, но неприятный сценарий — порт удерживает не сервис, а systemd-сокет. Приложение может даже не быть запущено, но порт уже зарезервирован unit-файлом типа .socket.

Проверьте активные сокеты:

sudo systemctl list-sockets --all | grep -E ':80|:443'

И дополнительно посмотрите список socket-unit:

systemctl list-unit-files | grep socket

Если выяснится, что порт держит какой-то socket-unit, останавливать и отключать нужно именно его, а не только связанный service-unit:

sudo systemctl stop example.socket
sudo systemctl disable example.socket

После этого снова выполните ss -ltnp. Это типичная ловушка: сервиса как будто нет, а порт всё равно занят.

Для обычного nginx на Debian и Ubuntu socket activation обычно не используется, но на сервере могут жить вспомогательные прокси, кастомные сервисы или вручную созданные unit-файлы.

Частый сценарий №5: Certbot, панели управления и автоматические изменения

Иногда конфликт появляется после автоматических действий: установки Certbot, панели управления, шаблона развёртывания или готового скрипта инициализации. Один компонент считает, что должен работать через Apache, другой — что через nginx.

В такой ситуации полезно проверить историю установленных пакетов и список активных сервисов:

dpkg -l | grep -E 'nginx|apache2|certbot'
sudo systemctl --type=service --state=running | grep -E 'nginx|apache2'

Если вы недавно настраивали HTTPS, внимательно проверьте, не активировался ли параллельный веб-сервер через плагин или зависимость пакета. А после восстановления работы не забудьте проверить базовые заголовки безопасности, о которых мы отдельно писали в статье про HTTP security headers в nginx и Apache.

Если проект ещё только разворачивается и нужно быстро поднять сайт с сертификатом, у Fastfox есть SSL-сертификаты для типовых веб-проектов без лишней ручной возни.

Разбор конфликта портов между Docker и nginx на сервере

Что делать, если занят не 80, а 443

Для порта 443 логика та же самая. Разница только в типичных конкурентах: старый Apache с SSL-vhost, Docker-контейнер с HTTPS, второй reverse proxy или тестовый стенд с альтернативным веб-сервером.

Проверки остаются стандартными:

sudo ss -ltnp '( sport = :443 )'
sudo lsof -nP -iTCP:443 -sTCP:LISTEN

Дополнительно проверьте конфигурацию nginx на дубли listen 443 ssl с одинаковыми адресами и конфликтующими параметрами. На серверах с большим числом vhost-файлов проблема часто всплывает после добавления нового сайта.

Как отличить конфликт процесса от ошибки конфигурации

Снаружи симптомы похожи, но подход к решению разный. Если порт реально занят чужим процессом, ss и lsof покажут владельца сокета даже при остановленном nginx. Если же конфликт внутри конфигурации, владелец сокета может быть сам nginx или ошибка будет воспроизводиться только на этапе теста конфига.

Практический порядок такой:

  1. Выполнить sudo nginx -t.
  2. Проверить sudo ss -ltnp '( sport = :80 or sport = :443 )'.
  3. Если порт свободен, искать дубли listen и ошибки в include-файлах.
  4. Если порт занят, разбираться с конкретным процессом или socket-unit.

Такой алгоритм почти всегда приводит к ответу быстрее, чем бессистемное чтение десятков файлов в /etc/nginx.

Безопасный runbook для production

Если сервер боевой и на нём уже крутятся сайты, лучше идти по короткому регламенту, чтобы не устроить лишний простой.

  1. Проверить конфигурацию: sudo nginx -t.
  2. Посмотреть владельца портов: sudo ss -ltnp '( sport = :80 or sport = :443 )'.
  3. Определить, это Apache, Docker, socket-unit или второй nginx.
  4. Понять, нужен ли этот сервис прямо сейчас.
  5. Только затем останавливать лишний сервис или менять публикацию порта.
  6. После освобождения порта запускать nginx.
  7. Проверить, что сервис реально слушает сокеты и отвечает локально.

Финальная проверка:

sudo systemctl restart nginx
sudo systemctl status nginx --no-pager
sudo ss -ltnp '( sport = :80 or sport = :443 )'
curl -I localhost
curl -kI https://localhost

Профилактика: как не ловить bind failed повторно

Полностью исключить такие конфликты нельзя, но их легко сделать редкими и предсказуемыми.

  • Назначьте один основной фронтенд на портах 80 и 443.
  • Не запускайте nginx вручную, если управляете им через systemd.
  • Для контейнеров публикуйте наружу только действительно нужные порты.
  • Храните конфиги веб-сервера и compose-файлы в Git.
  • После установки новых пакетов проверяйте, какие сервисы включились автоматически.
  • Документируйте карту портов для команды.

На серверах с несколькими проектами особенно полезно заранее описать, какой сервис слушает внешний трафик, какой работает только на localhost, а какой доступен лишь во внутренней сети контейнеров. Тогда ошибка bind failed превращается из аварии в рутинный кейс.

Итог

Сообщение nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use) в Debian и Ubuntu почти всегда сводится к одному из нескольких сценариев: порт занят Apache, Docker-контейнером, другим экземпляром nginx или systemd-сокетом. Реже причина скрыта в дублирующейся конфигурации самого nginx.

Самый короткий путь к решению — не гадать, а сразу проверить конфиг и владельца сокета:

sudo nginx -t
sudo ss -ltnp '( sport = :80 or sport = :443 )'
sudo lsof -nP -iTCP:80 -sTCP:LISTEN
sudo lsof -nP -iTCP:443 -sTCP:LISTEN

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

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

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

Debian/Ubuntu: как исправить Nginx no live upstreams while connecting to upstream OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Nginx no live upstreams while connecting to upstream

Ошибка Nginx no live upstreams while connecting to upstream означает, что веб-сервер не видит доступных backend-процессов. Ниже — ...
ERR_TOO_MANY_REDIRECTS в Nginx и Apache за reverse proxy на Debian/Ubuntu: где искать цикл редиректов OpenAI Статья написана AI (GPT 5)

ERR_TOO_MANY_REDIRECTS в Nginx и Apache за reverse proxy на Debian/Ubuntu: где искать цикл редиректов

Если сайт уходит в ERR_TOO_MANY_REDIRECTS, причина обычно в конфликте редиректов между Nginx, Apache, приложением, CDN или reverse ...
Debian/Ubuntu: Too many levels of symbolic links — как найти и исправить зацикленный symlink OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: Too many levels of symbolic links — как найти и исправить зацикленный symlink

Ошибка Too many levels of symbolic links в Debian/Ubuntu почти всегда означает цикл в символьных ссылках или ошибку в структуре de ...