SSH-сессия обрывается после пары минут простоя с «client_loop: send disconnect: Broken pipe»: кто рвёт соединение и как держать его живым

Что было. Подключение по SSH к серверу работает, но стоит отвлечься на несколько минут, терминал выдаёт client_loop: send disconnect: Broken pipe и сессия закрыта. Работать приходится, постоянно нажимая клавиши.

Кто виноват. Обычно не сервер и не клиент, а что-то между ними: домашний маршрутизатор, NAT оператора, корпоративный брандмауэр или балансировщик, который забывает простаивающее TCP-соединение через 1–5 минут и молча выбрасывает следующие пакеты. Клиент узнаёт об этом при первой попытке что-то отправить, отсюда «Broken pipe».

Решение, подтверждённое участником. Заставить клиент периодически посылать служебные пакеты, чтобы соединение не считалось простаивающим:

# ~/.ssh/config
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Каждые 60 секунд клиент шлёт запрос внутри зашифрованного канала; после трёх без ответа сам закрывает сессию (то есть сессия переживёт короткий обрыв, но не будет висеть вечно). Одноразово то же самое ssh -o ServerAliveInterval=60 user@host. В обсуждении использовали интервал 600 секунд; для устройств с агрессивным таймаутом лучше 30–60.

Со стороны сервера та же логика в /etc/ssh/sshd_config:

ClientAliveInterval 60
ClientAliveCountMax 3

Это помогает всем клиентам сразу, включая тех, у кого нет доступа к своему конфигу (мобильные приложения, автоматизация). После правки sshd -t и systemctl reload ssh.

TCPKeepAlive не то же самое. Он работает на уровне TCP, без шифрования, легко отбрасывается промежуточными устройствами и не защищает от подмены. ServerAlive/ClientAlive идут внутри SSH-канала, и их стоит предпочесть.

Если обрывы остаются даже с keepalive.

  • Обрывы ровно при передаче большого вывода: проблема с MTU на пути, помогает IPQoS throughput в клиентском конфиге или уменьшение MTU на интерфейсе.
  • Обрывы при переключении сети на ноутбуке (Wi-Fi ↔ кабель, сон): это смена адреса, TCP этого не переживает; спасают tmux/screen на сервере или клиенты с автопереподключением (mosh, autossh).
  • Обрыв через фиксированное время активной работы: смотреть лимиты на стороне сервера (ClientAliveCountMax 0 в старых конфигах означает «не отключать», в новых версиях OpenSSH семантика изменилась) и политики брандмауэра.

Для долгих операций (обновление, миграция, сборка) вне зависимости от keepalive: tmux new -s work, внутри запускать команду; при обрыве tmux attach -t work вернёт сессию.

Параметр описан в документации OpenSSH.