socat: проброс Unix-сокетов через TCP
Иногда нужно обратиться к Unix-сокету с хоста, где этот сокет физически не существует. SSH-туннель не поможет — он работает с TCP-портами. socat решает эту задачу: поднимает TCP- listener и пробрасывает соединения в Unix-сокет, а клиенту достаточно подключиться по сети.
Установка
Пакет есть в любом крупном дистрибутиве. На Debian/Ubuntu:
На RHEL/CentOS:
Alpine:
Проверка:
Базовый проброс: TCP-LISTEN + UNIX-CONNECT
Серверная сторона. Слушаем TCP-порт и при подключении перенаправляем трафик в Unix-сокет:
Флаги:
TCP-LISTEN:2375— открываем порт 2375fork— порождаем дочерний процесс на каждое подключение; без него socat примет одно соединение и выйдет
На клиенте работаем как обычно — например, curl к Docker API:
Если клиент на удалённом хосте, укажите IP сервера:
Docker по умолчанию слушает только локальный сокет. Открывать TCP-LISTEN наружу без TLS или firewall — риск. Ограничьте бинд интерфейсом: TCP-LISTEN:2375,bind=127.0.0.1.
Остановить проброс — Ctrl+C или kill по PID.
Клиентский тест через STDIO
Если нужно быстро проверить доступность сокета или отправить ручную команду, используйте STDIO на стороне клиента:
После запуска вводите сырые HTTP-запросы. Пример сессии:
Выход — Ctrl+D или Ctrl+C. Это удобно для отладки API без curl и без настройки переменных окружения.
Для TCP-соединения по сети клиент запускается симметрично:
Abstract vs Filesystem сокеты
Unix-сокеты бывают двух типов. Разница принципиальна для работы socat.
Filesystem sockets — привязаны к файловой системе. Путь начинается с /:
Abstract sockets — живут в памяти ядра, не имеют файлового представления. Путь начинается с \0 или @ (ASCII zero и at-символ). Docker в rootless-режиме использует именно их:
Проверить тип сокета:
В socat синтаксис:
@/path/to/socket— абстрактный сокет/path/to/socket— файловый сокет
Абстрактные сокеты невидимы для процессов без доступа к namespace. Это плюс для изоляции, но осложняет проброс между контейнерами.
Timeout-флаги
По умолчанию socat ждёт вечно. Для автоматизации и скриптов нужны таймауты.
| Флаг | Описание |
|---|---|
readtimeout=SECONDS | Таймаут на чтение |
writetimeout=SECONDS | Таймаут на запись |
timeout=SECONDS | Таймаут на обе операции |
Пример с общим таймаутом:
Соединение закроется через 30 секунд неактивности.
Раздельные таймауты для клиента и сервера:
В cron-скриптах или systemd-юнитах ставьте таймаут, иначе процесс повиснет при обрыве сети:
Для бесконечного ожидания без fork подойдёт forever, но в продакшене лучше комбинировать с system limits:
reuseaddr позволяет быстро перезапустить socat без ошибки «Address already in use».
Типичные ошибки
Permission denied при доступе к сокету
Connection refused
Проверьте, что socat запущен и слушает порт:
Фаерволл:
Один запрос — и socat умирает
Отсутствует fork. Каждый socat обрабатывает одно соединение и выходит. Добавьте флаг:
Абстрактный сокет не найден
Убедитесь в правильном префиксе. Docker в rootless использует @, но это ASCII 0:
В socat пишите @/docker.sock, не @@/docker.sock.
Systemd-сервис для постоянного проброса
Если нужен постоянный проброс, оберните в systemd-юнит:
Не забудьте ограничить бинд интерфейсом, если не хотите открывать порт наружу.
Вместо заключения
socat — это unix way для прозрачного проброса чего угодно куда угодно. Для Unix-сокетов через TCP достаточно двух процессов и минуты настройки. Держите таймауты, не забывайте fork, и не открывайте порты без авторизации в public network.