
Следовать за:Похоже, что быстрая серия отключений, совпадающая с несколькими месяцами работы каждого сервера, вероятно, является совпадением и просто служит для выявления фактической проблемы. Причина, по которой он не смог переподключиться, почти наверняка кроется в значениях AliveInterval (ответ kasperd). Использование параметра ExitOnForwardFailure должно позволить тайм-ауту правильно произойти перед переподключением, что должно решить проблему в большинстве случаев. Предложение MadHatter (скрипт kill) — это, вероятно, лучший способ убедиться, что туннель может переподключиться, даже если все остальное не работает.
У меня есть сервер (A) за брандмауэром, который инициирует обратный туннель на нескольких портах к небольшому DigitalOcean VPS (B), чтобы я мог подключиться к A через IP-адрес B. Туннель работал стабильно около 3 месяцев, но внезапно четыре раза за последние 24 часа вышел из строя. То же самое произошло некоторое время назад у другого провайдера VPS — месяцы идеальной работы, а затем внезапно несколько быстрых сбоев.
У меня есть скрипт на машине A, который автоматически выполняет команду туннеля ( ssh -R *:X:localhost:X address_of_B
для каждого порта X), но при выполнении он выдает Warning: remote port forwarding failed for listen port X
.
При входе в sshd /var/log/secure
на сервере появляются следующие ошибки:
bind: Address already in use
error: bind: Address already in use
error: channel_setup_fwd_listener: cannot listen to port: X
Решение требует перезагрузки VPS. До этого все попытки переподключения будут выдавать сообщение "удаленная переадресация порта не удалась" и не будут работать. Сейчас дошло до того, что туннель работает всего около 4 часов, прежде чем остановиться.
На VPS ничего не изменилось, и это машина для одного пользователя, которая служит только конечной точкой обратного туннеля. На ней запущен OpenSSH_5.3p1 на CentOS 6.5. Похоже, что sshd не закрывает порты на своем конце, когда соединение теряется. Я не могу объяснить, почему, или почему это внезапно произошло сейчас после месяцев почти идеальной работы.
Чтобы прояснить ситуацию, мне сначала нужно выяснить, почему sshd отказывается прослушивать порты после сбоя туннеля, что, похоже, вызвано тем, что sshd оставляет порты открытыми и никогда их не закрывает. Похоже, это главная проблема. Я просто не уверен, что могло заставить его вести себя таким образом после месяцев поведения, как я и ожидал (т. е. немедленного закрытия портов и разрешения скрипту переподключиться).
решение1
Я согласен с MadHatter, что это, скорее всего, переадресация портов из неработающих ssh-соединений. Даже если ваша текущая проблема окажется чем-то другим, вы можете ожидать, что рано или поздно столкнетесь с такими неработающими ssh-соединениями.
Существует три способа, при помощи которых такие несуществующие связи могут возникнуть:
- Одна из двух конечных точек была перезагружена, в то время как другой конец соединения полностью бездействовал.
- Одна из двух конечных точек закрыла соединение, но в то время, когда соединение было закрыто, произошел временный сбой в соединении. Сбой продолжался несколько минут после закрытия соединения, и, таким образом, другой конец так и не узнал о закрытом соединении.
- Соединение по-прежнему полностью функционально на обеих конечных точках соединения ssh, но кто-то поместил устройство с отслеживанием состояния где-то между ними, что привело к тайм-ауту соединения из-за простоя. Это устройство с отслеживанием состояния может быть либо NAT, либо брандмауэром, упомянутый вами брандмауэр — главный подозреваемый.
Выяснение того, какой из трех вышеперечисленных вариантов имеет место, не так уж и важно, поскольку существует метод, который решит все три проблемы. Это использование сообщений keepalive.
Вам следует обратить внимание на ClientAliveInterval
ключевое слово for sshd_config
и ServerAliveInterval
интервал для ssh_config
or ~/.ssh/config
.
Запуск ssh
команды в цикле может работать нормально. Хорошей идеей будет также вставить сон в цикл, чтобы не перегружать сервер, когда соединение по какой-то причине лопнет.
Если клиент переподключится до того, как соединение прервется на сервере, вы можете оказаться в ситуации, когда новое ssh-подключение будет активным, но не будет иметь переадресации портов. Чтобы этого избежать, вам нужно использовать ключевое ExitOnForwardFailure
слово на стороне клиента.
решение2
Для меня, когда ssh
туннель отключается, требуется некоторое время для сброса соединения, поэтому ssh
процесс продолжает блокироваться, оставляя меня без активных туннелей, и я не знаю, почему. Обходное решение — перевести ssh
в фоновый режим -f
и создавать новые соединения, не дожидаясь сброса старых соединений. Можно -o ExitOnForwardFailure=yes
использовать для ограничения количества новых процессов. Повышает -o ServerAliveInterval=60
надежность текущего соединения.
Вы можете повторять ssh
команду часто, скажем, в cron
, или в цикле вашего скрипта, например, в следующем примере мы запускаем ssh
команду каждые 3 минуты:
while (1)
do
ssh -f user@hostname -Rport:host:hostport -N -o ExitOnForwardFailure=yes -o ServerAliveInterval=60
sleep 180
done
решение3
Вы можете найти процесс, который привязывает порт на этом сервере, с помощью
sudo netstat -apn|grep -w X
Кажется, что это, скорее всего, half-defunct sshd
, но зачем делать предположения, когда можно иметь данные? Это также хороший способ для скрипта найти PID, чтобы отправить сигнал 9, прежде чем пытаться снова поднять туннель.
решение4
По моему опыту, ssh имеет немного раздражающую привычку не завершаться чисто, если на удаленной системе все еще работает «что-то». Например, запущено в фоновом режиме. Вы можете воспроизвести это так:
ssh <server>
while true; do sleep 60; done&
exit
Ваш ssh выйдет из системы, но на самом деле не закроет сеанс — пока удаленный процесс не завершится (чего не произойдет, поскольку это цикл «while true»). Возможно, происходит что-то похожее — в вашем сеансе есть «застрявший» процесс, который порождается ssh. Порт остается занятым, и поэтому он не может быть повторно использован вашим локальным процессом.