Служба не получает сокет при сокет-активации
При сокет-активации systemd открывает адрес сам и передаёт готовый дескриптор службе начиная с номера 3, сообщая их количество в переменных LISTEN_FDS и LISTEN_PID. Если служба этого не ожидает или имена unit не совпадают, она пытается открыть порт сама — и получает отказ или работает не через сокет.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Программа не умеет принимать готовый дескриптор
Сокет-активация требует поддержки со стороны программы. Без неё служба просто откроет свой порт, а сокет systemd останется незадействованным — или займёт порт первым.
-
Имена сокета и службы не совпадают
По умолчанию
myapp.socketактивируетmyapp.service. При других именах нужен параметрService=в сокете. -
Указан
Accept=yes, а служба ждёт слушающий сокетПри
Accept=yessystemd принимает соединение и запускает отдельный экземпляр службы на каждое, передавая уже установленное соединение. Обычной сетевой службе нуженAccept=no. -
Служба ищет дескриптор по имени, а имя не задано
Программы, работающие с несколькими сокетами, различают их по именам из
FileDescriptorName=. Без имени они не находят нужный.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Показывает адрес, сокет и активируемую им службу — сразу видно расхождение имён.
systemctl list-sockets --no-pagerТри параметра, от которых зависит передача дескриптора.
systemctl show myapp.socket -p Accept -p Service -p FileDescriptorNameЖурналы сокета и службы вместе: видно порядок событий при активации.
journalctl -u myapp.socket -u myapp.service -n 40 --no-pagerРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- Сокет-активация требует поддержки со стороны программы. Без неё служба просто откроет свой порт, а сокет systemd останется незадействованным — или займёт порт первым.
- Как проверить
-
Посмотрите, что делает служба при запуске, и переменные окружения.
systemctl show myapp.service -p Sockets sudo ss -tlnp | grep 8080
- Как исправить
- Либо откажитесь от сокет-активации и пусть служба слушает сама, либо используйте программу, которая поддерживает передачу дескрипторов.
- Почему происходит
- По умолчанию
myapp.socketактивируетmyapp.service. При других именах нужен параметрService=в сокете.
- Как проверить
-
Посмотрите, какую службу активирует сокет.
systemctl show myapp.socket -p Service systemctl show myapp.service -p Sockets
- Как исправить
-
Укажите связь явно параметром
Service=в секции [Socket].[Socket] Service=backend.service
Accept=yes, а служба ждёт слушающий сокет- Почему происходит
- При
Accept=yessystemd принимает соединение и запускает отдельный экземпляр службы на каждое, передавая уже установленное соединение. Обычной сетевой службе нуженAccept=no.
- Как проверить
-
Посмотрите значение параметра.
systemctl show myapp.socket -p Accept
- Как исправить
-
Для служб, которые сами обслуживают много соединений, поставьте
Accept=no. Режим по соединению подходит только простым обработчикам.
- Почему происходит
- Программы, работающие с несколькими сокетами, различают их по именам из
FileDescriptorName=. Без имени они не находят нужный.
- Как проверить
-
Посмотрите имена дескрипторов у сокета.
systemctl show myapp.socket -p FileDescriptorName
- Как исправить
-
Задайте
FileDescriptorName=в [Socket] так, как ожидает программа.
Пример вывода
Служба пытается открыть порт, уже занятый сокетом systemd. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
● myapp.socket - Socket for myapp
Active: active (listening) since Mon 2026-09-15 12:00:02 MSK; 5min ago
Listen: 127.0.0.1:8080 (Stream)
× myapp.service - My application
Active: failed (Result: exit-code)
myapp[6100]: fatal: listen tcp 127.0.0.1:8080: bind: address already in use
Связанные ошибки
- Сокет без Listen: unit загружен, но ничего не слушает В .socket не задан ни один параметр Listen…= — сокет не принимает соединения. Как объявить адрес прослушивания.
- Address already in use при запуске службы Порт или адрес уже занят: bind() failed (98: Address already in use). Как найти владельца порта и что делать с остатками прежнего процесса.
- status=202/FDS в systemd Код 202/FDS: systemd не смог закрыть лишние файловые дескрипторы или настроить переданные. Причины и проверка.
- Сокет и служба включены одновременно: конфликт при загрузке При сокет-активации в автозапуск включена и служба, и сокет. Порт занимает то, что стартовало первым.
- Bad file descriptor в журнале службы Ошибка 9 при операции с файлом: дескриптор закрыт или не тот. Разбор для служб и сокет-активации.
- File exists при создании файла или сокета Ошибка 17: объект уже существует. Разбор для сокетов, файлов блокировки и каталогов службы.
- MySQL: Can't connect to local server through socket Клиент не находит unix-сокет MySQL: сервер не запущен, путь к сокету другой, каталог в /run не создан.
- Puma слушает сокет, а веб-сервер получает отказ доступа Разъём между приложением и веб-сервером: сокет создаётся с правами приложения, читает его другой пользователь.
Где встречается чаще всего
Источники
-
systemd.socket(5)
Accept=, Service=, FileDescriptorName= и передача дескрипторов. -
sd_listen_fds(3)
Как программа получает переданные сокеты. -
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено связкой сокета и службы, открывающей порт самостоятельно.