Docker на Windows 11: «ports are not available… Forbidden by its access permissions» — как починить раз и навсегда

bind: An attempt was made to access a socket in a way forbidden by its access permissions.

Если вы активно используете Docker на Windows 11 (особенно в связке с WSL2 или Hyper-V), вы наверняка хотя бы раз ловили странную ошибку при попытке пробросить порт:

Error response from daemon: ports are not available: exposing port TCP 0.0.0.0:18080 -> 127.0.0.1:0:
listen tcp 0.0.0.0:18080: bind: An attempt was made to access a socket in a way forbidden by its access permissions.

Первое, что делает любой разработчик в такой ситуации — открывает терминал и проверяет, кто занял порт:

netstat -aon | findstr PORT

А в ответ — тишина. Никакой процесс не слушает этот порт. И тем не менее Docker упорно отказывается его занимать. Дело в том, что проблема здесь вообще не в занятости порта — она на уровне операционной системы.

В чём корень проблемы

Сообщение «An attempt was made to access a socket in a way forbidden by its access permissions» означает, что порт заблокирован самой Windows. Виновник — служба WinNAT (Windows NAT-драйвер), которую используют Hyper-V и WSL2 для организации сетевого взаимодействия с виртуальными машинами.

Чтобы виртуализация работала корректно, Windows резервирует под свои нужды так называемые excluded port ranges — диапазоны исключений среди динамических портов. По умолчанию эти диапазоны могут начинаться с произвольной позиции: с 1024, с 10000 или вообще откуда-то из середины. Если ваш рабочий порт (8080, 3000, 5432, 18080 — что угодно) случайно попадает в один из таких интервалов, Windows просто запретит любому стороннему софту, включая Docker, к нему прикасаться.

Самое неприятное — после каждой перезагрузки Windows может переразмечать эти диапазоны заново, и проблема «гуляет» от сессии к сессии.

Шаг 1. Диагностика

Чтобы убедиться, что причина именно в резервировании, откройте PowerShell от имени Администратора и выполните:

netsh int ipv4 show excludedportrange protocol=tcp

На экране появится таблица с диапазонами портов, которые Windows считает «своими»:

Протокол tcp, диапазоны исключений портов

Стартовый порт    Конечный порт
--------------    -----------
        17005           17104
        18000           18100   <- вот тут застрял ваш например 18080
        50000           50059

Если нужный порт попадает в любой из этих интервалов — система его не отдаст. Переходим к решению.

Вариант 1. Быстрый костыль на один раз

Если контейнер нужно поднять прямо сейчас, а разбираться с настройками некогда, можно принудительно перезапустить службу NAT. WinNAT при перезапуске сбросит текущие резервации и выделит новые — скорее всего, в другом месте, и нужный порт освободится.

Откройте PowerShell от имени Администратора:

# Останавливаем WinNAT (уже запущенные контейнеры временно потеряют сеть)
net stop winnat

# Запускаем контейнер, пока порт свободен
docker compose up -d

# Возвращаем службу NAT на место
net start winnat

Минус: после следующей перезагрузки Windows снова может забрать ваш порт. Так что это именно «побыстрее починить», а не решение.

Вариант 2. Решение навсегда

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

Запускаем PowerShell от имени Администратора и выполняем три команды:

# 1. Останавливаем службу NAT, которая держит порты
net stop winnat

# 2. Сдвигаем диапазон динамических портов в конец TCP-пространства
netsh int ipv4 set dynamicport tcp start=49152 num=16384

# 3. Возвращаем WinNAT в работу
net start winnat

Что произошло

Мы установили стартовую точку динамических портов на 49152 и выделили под системные нужды 16384 порта — ровно до верхней границы TCP-диапазона (65535). Всё, что ниже 49152, теперь гарантированно свободно от посягательств Windows: популярные 80, 443, 3000, 3306, 5432, 8080, 8443, 18080 — все остаются за вами и вашими приложениями.

Настройка переживает перезагрузки и обновления Windows, потому что записывается в реестр.

Как убедиться, что всё сработало

После выполнения команд снова запросите список диапазонов исключений:

netsh int ipv4 show excludedportrange protocol=tcp

Все интервалы теперь должны стартовать с порта 49152 или выше. Можно спокойно пробрасывать любые «разработческие» порты в Docker.

Краткая шпаргалка

  • Виновник: WinNAT (Hyper-V / WSL2) резервирует динамические порты.
  • Диагностика: netsh int ipv4 show excludedportrange protocol=tcp.
  • Быстрый фикс: net stop winnatdocker compose upnet start winnat.
  • Навсегда: netsh int ipv4 set dynamicport tcp start=49152 num=16384 (между stop/start WinNAT).

Одна минута в PowerShell — и Docker больше никогда не споткнётся о зарезервированный Windows порт.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *