Вопрос Как надежно сохранить SSH-туннель открытым?


Я использую туннель SSH от работы, чтобы обойти различные идиотские брандмауэры (это нормально с моим боссом :)). Проблема в том, что через некоторое время соединение ssh обычно зависает, а туннель прерывается.

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

Бонусные очки для того, кто может сказать мне, как предотвратить мое свидание ssh, конечно!


200
2017-09-08 13:04


происхождения


Это твой туннель мертв, потому что бездеятельность? У меня была эта проблема при туннелировании портов с моего телефона, поэтому я, наконец, закончил порождать фиктивные команды в соединении, чтобы сделать его «живым», используя watch команда вроде: watch -n1 60 echo "wiiiii", Туннель не погибнет, если сеть не сломалась или вы ее не используете. - erm3nda
Связанный: unix.stackexchange.com/q/200239 - sampablokuper


ответы:


Похоже, что вам нужно autossh, Это будет контролировать туннель ssh и перезапустить его по мере необходимости. Мы использовали его в течение нескольких лет, и, похоже, он работает хорошо.

autossh -M 20000 -f -N your_public_server -R 1234:localhost:22 -C

Подробнее о параметре -M Вот


239
2017-09-08 13:43



+1 для autossh, он делает то, что говорит на олове. Я считаю, что часть его функциональности также заключается в том, чтобы отправлять пакеты стиля keep-alive, чтобы предотвратить любой тайм-аут. - akent
Не могли бы вы использовать пример туннеля, используя autossh в ответ? - Ehtesh Choudhury
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com   Вы могли заметить, что я установил это с помощью -nNT, который не создает удаленный терминал, чтобы я мог поместить autossh в фоновый режим, и параметр -i для SSH для использования файла .pem. Если вы собираетесь постоянно поддерживать связь, я определенно рекомендую пройти дополнительную настройку. - juckele
Для чего это стоит, похоже, что обычно лучше опустить -M параметр: bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162 - rinogo
Если он не работает и вы используете ключи, проверьте этот ответ - serverfault.com/a/545093/288788 - muttonUp


Все брандмауэры с сохранением состояния забывают о соединении после того, как не видели пакет для этого соединения в течение некоторого времени (чтобы таблицы состояний не заполнились соединениями, где оба конца умерли, не закрывая соединение). Большинство реализаций TCP отправляют пакет keepalive через долгое время без прослушивания с другой стороны (2 часа - это общее значение). Если, однако, существует брандмауэр с состоянием, который забывает о соединении, прежде чем пакеты keepalive могут быть отправлены, долговременное, но бездействующее соединение умрет.

Если это так, решение состоит в том, чтобы предотвратить простоя соединения. У OpenSSH есть опция, называемая ServerAliveInterval который может быть использован для предотвращения слишком длительного простоя соединения (в качестве бонуса он обнаружит, когда сверстник умер раньше, даже если соединение простаивает).


34
2017-09-28 13:47



Интервал указан в секундах, поэтому вы можете обеспечить точную настройку. Если ваш брандмауэр с состоянием имеет 5-минутный тайм-аут простоя, то для поддержания соединения достаточно 60 или 120 секунд. Это один из способов сохранить мои сеансы ssh через мой домашний маршрутизатор. - Darren Hall
Спасибо, это помогло. Но обратите внимание (из нижеприведенного ответа здесь, superuser.com/a/146641/115515), что если вы укажете ServerAliveInterval, а не ServerAliveCountMax, вы можете найти ssh намеренно отключаться раньше, чем вы хотели. - metamatt
@metamatt, этот более низкий рейтинг, на который вы ссылаетесь, находится ниже по веским причинам: это НЕПРАВИЛЬНО. - Lambart


На своей собственной машине mac или linux настройте свой ssh, чтобы сервер ssh был жив каждые 3 минуты. Откройте терминал и запустите свой невидимый .ssh в своем доме:

cd ~/.ssh/ 

затем создайте файл с 1 строчной конфигурацией с:

echo "ServerAliveInterval 180" >> config

вы также должны добавить:

ServerAliveCountMax xxxx (high number)

по умолчанию 3, поэтому ServerAliveInterval 180 прекратит отправку через 9 минут (3 из 3-минутного интервала, указанного ServerAliveInterval).


22
2018-05-29 13:45



Обратите внимание, что ваша команда не рекомендуется, если у вас уже есть файл конфигурации. Использование >> для перенаправления было бы намного лучше! - Peltier
Почему ServerAliveInterval 180 дайте нам 6 минут? интуиция заставляет меня попробовать это: 180/60 == 3, Итак, ServerAliveInterval работать в кратных 30 секунд? - nemesisfixx
@mcnemesis: ServerAliveInterval 180 означает 3 минуты. ServerAliveCountMax по умолчанию 3 означает 3 из этих интервалов, поэтому 9 минут. - metamatt
Я проголосовал за этот ответ, потому что спасибо за упоминание ServerAliveCountMax, и что произойдет, если вы укажете ServerAliveInterval без ServerAliveCountMax. Но, как и предыдущие комментарии, я замечаю, что вычисление на «перестанет посылать после» неверно, и я думаю, что этот ответ будет лучше, если он просто предоставил информацию об этих параметрах, не сообщив нам, как применять их с помощью команд cd и echo , - metamatt
Downvoting, потому что нет смысла устанавливать ServerAliveCountMax на «большое число». ServerAliveCountMax указывает, сколько раз он попытается отправить сообщение «keepalive» перед тем, как отказаться. Значение по умолчанию равно 3, поэтому с ServerAliveInterval 180 он прекратит отправку ТОЛЬКО, если сервер НЕ ОТВЕЧАЕТ через 9 минут, и в этом случае ваше соединение, вероятно, будет действительно и действительно мертвым. - Lambart


Я использовал следующий скрипт Bash, чтобы поддерживать нереста новых туннелей ssh, когда предыдущий умирает. Использование сценария удобно, если вы не хотите или не можете устанавливать дополнительные пакеты или использовать компилятор.

while true
do
  ssh <ssh_options> [user@]hostname
  sleep 15
done

Обратите внимание, что для этого требуется, чтобы ключевой файл устанавливал соединение автоматически, но это также относится к autossh.


20
2017-09-22 14:58



Вы должны добавить какие-либо причины, по которым вы бы использовали этот скрипт поверх autossh, или просто так проще? - kyrias
Это не помогло бы, если бы ssh замерзала, не так ли? - nafg
Это помогает, если вы не можете установить вещи на сервере. autossh не приходит предустановленной, а бюрократия иногда бывает очень тупой. - quarkex
Да, предпочтительнее не устанавливать вещи. Я делаю это так в течение года, так как единственный способ сохранить доступ к удаленной машине (даже установить crontab для запуска при перезагрузке). Это никогда не проваливалось, и, что более важно, я знаю, почему это никогда не потерпит неудачу. - sudo


Мне кажется, что вы все неправильно интерпретируете ServerAliveCountMax. Насколько я понимаю документы, это число активных сообщений сервера, которые могут оставаться без ответа без прекращения соединения. Поэтому в таких случаях, как мы обсуждаем здесь, установив его на высокое значение, вы просто убедитесь, что повесившееся соединение не будет обнаружено и прекращено!

Простое задание ServerAliveInterval должно быть достаточным для решения проблемы с брандмауэром, забывающим о соединении, и оставив ServerAliveCountMax низким, позволит исходному концу заметить сбой и прекратить работу, если соединение в любом случае потерпит неудачу.

То, что вы хотите, 1) для того, чтобы соединение оставалось открытым постоянно при нормальных обстоятельствах, 2) для обнаружения отказа соединения и исходящей стороны для выхода из отказа, и 3) для повторной выдачи команды ssh каждый раз выходы (как вы это делаете, это зависит от платформы, сценарий «while true», предложенный Jawa, является одним из способов, поскольку OS XI фактически настроил элемент launchd).


9
2017-11-28 01:04





Всегда используйте ServerAliveInterval SSH в случае, если проблемы туннеля генерируются с помощью сеансов NAT с истекшим сроком действия.

Всегда используйте метод респаунирования в случае, если соединение полностью опускается, у вас есть как минимум три варианта:

  • программа autossh
  • скрипт bash (while true do ssh ...; sleep 5; done) не удаляют команду спящего режима, ssh может быстро выйти из строя, и вы будете повторно запускать слишком много процессов
  • /etc/inittab, чтобы иметь доступ к коробке, поставляемой и установленной в другой стране, за NAT, без пересылки порта в коробку, вы можете настроить его для создания туннеля ssh для вас:

    tun1:2345:respawn:/usr/bin/ssh -i /path/to/rsaKey -f -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip 'sleep 365d'
    
  • сценарий upstart на Ubuntu, где /etc/inittab недоступно:

    start on net-device-up IFACE=eth0
    stop on runlevel [01S6]
    respawn
    respawn limit 180 900
    exec ssh -i /path/to/rsaKey -N -o "ServerAliveInterval 180" -R 55002:localhost:22 user@publicip
    post-stop script
        sleep 5
    end script
    

или всегда используйте оба метода.


9
2018-03-08 21:30



+1 для встроенного варианта, если вы не хотите его для всех ваших соединений SSH - user1146334
Вы пишете «в случае, если соединение полностью опускается». Теперь я не понимаю, какие проблемы делает autossh, а что нет? Я думал, что, конечно, это позаботится о любом сломанном соединении, например, отсоединении кабеля в течение нескольких часов, но, возможно, нет? - Mads Skjern


Systemd идеально подходит для этого.

Создать файл службы /etc/systemd/system/sshtunnel.service содержащий:

[Unit]
Description=SSH Tunnel
After=network.target

[Service]
Restart=always
RestartSec=20
User=sshtunnel
ExecStart=/bin/ssh -NT -o ServerAliveInterval=60 -L 5900:localhost:5900 user@otherserver

[Install]
WantedBy=multi-user.target

(Измените команду ssh, чтобы она соответствовала)

  • это будет работать как пользователь sshtunnel поэтому убедитесь, что пользователь существует первым
  • вопрос systemctl enable sshtunnel установить его во время загрузки
  • вопрос systemctl start sshtunnel немедленно начать

Обновление января 2018 года: некоторые дистрибутивы (например, Fedora 27) могут использовать политику SELinux, чтобы предотвратить использование SSH из systemd init, и в этом случае необходимо создать настраиваемую политику для предоставления необходимых исключений.


8
2017-07-28 06:10



Это очень похоже на мой смысл: gist.github.com/guettli/... Обратная связь приветствуется! - guettli
Отлично подходит для systemd система. Если вы используете Restart=on-failure то ручное убийство SSH-клиента не приведет к перезапуску по системе в качестве SSH-клиента с успешным выходом. - David Tonhofer
Если вы хотите запустить ssh из сценария (bash), указанного в качестве аргумента для ExecStart например, для создания ssh список аргументов, выполнить базовые проверки и т. д., затем вызвать его из сценария так exec /bin/ssh -N ..., Вот моя команда: exec /bin/ssh -N -oExitOnForwardFailure=Yes -oTCPKeepAlive=no -oServerAliveInterval=5 -oServerAliveCountMax=6 -i "${LOCAL_PRIVATE_KEY}" -L "${TUNNEL_INLET}:${TUNNEL_OUTLET}" "${REMOTE_USER}@${REMOTE_MACHINE}" где TUNNEL_INLET="127.0.0.1:3307" а также TUNNEL_OUTLET="127.0.0.1:3306" - David Tonhofer


Я решил эту проблему:

редактировать

~/.ssh/config

И добавить

ServerAliveInterval 15
ServerAliveCountMax 4

В соответствии с справочная страница для ssh_config:

ServerAliveCountMax
         Sets the number of server alive messages (see below) which may be
         sent without ssh(1) receiving any messages back from the server.
         If this threshold is reached while server alive messages are
         being sent, ssh will disconnect from the server, terminating the
         session.  It is important to note that the use of server alive
         messages is very different from TCPKeepAlive (below).  The server
         alive messages are sent through the encrypted channel and there‐
         fore will not be spoofable.  The TCP keepalive option enabled by
         TCPKeepAlive is spoofable.  The server alive mechanism is valu‐
         able when the client or server depend on knowing when a connec‐
         tion has become inactive.

         The default value is 3.  If, for example, ServerAliveInterval
         (see below) is set to 15 and ServerAliveCountMax is left at the
         default, if the server becomes unresponsive, ssh will disconnect
         after approximately 45 seconds.  This option applies to protocol
         version 2 only.

 ServerAliveInterval
         Sets a timeout interval in seconds after which if no data has
         been received from the server, ssh(1) will send a message through
         the encrypted channel to request a response from the server.  The
         default is 0, indicating that these messages will not be sent to
         the server.  This option applies to protocol version 2 only.

6
2018-05-30 13:32



Каждые 15 секунд кажется довольно часто пинговать сервер. - Lambart
@Lambart, но если соединение действительно шелушится и часто удаляет соединения, оно, по крайней мере, обнаруживает мертвое соединение и дает возможность повторить попытку раньше. - binki


ExitOnForwardFailure yes является хорошим дополнением к другим предложениям. Если он подключается, но не может установить переадресацию порта, он просто бесполезен для вас, как если бы он вообще не подключался.


3
2018-06-06 23:41



Это очень хорошая идея. Даже autossh бесполезен, если предыдущее соединение воспринимается как ранее установленное на удаленной стороне, чем на локальном хосте, поскольку в этом случае локальный хост попытается подключиться снова, но пересылка не может быть установлена, потому что порт все еще открыт. - Raúl Salinas-Monteagudo


Мне нужно было долгое время поддерживать SSH-туннель. Мое решение запускалось с Linux-сервера, и это всего лишь небольшая программа на C, которая обновляет ssh, используя проверку подлинности на основе ключа.

Я не уверен в подвеске, но у меня были туннели из-за тайм-аутов.

Я хотел бы предоставить код для респауна, но я не могу найти его прямо сейчас.


1
2017-09-08 13:17