SSH 터널을 안정적으로 유지하는 방법?


234

직장에서 SSH 터널을 사용하여 다양한 idotic 방화벽을 돌아 다닙니다 (상사에게 괜찮습니다 :). 문제는 잠시 후 ssh 연결이 일반적으로 중단되고 터널이 손상되었다는 것입니다.

최소한 터널을 자동으로 모니터링 할 수 있다면 터널이 멈췄을 때 터널을 다시 시작할 수 있지만 그 방법을 찾지 못했습니다.

물론 내 ssh 연결이 중단되는 것을 방지하는 방법을 알려주는 사람에게는 보너스 포인트!


비 활동으로 인해 터널이 죽었습니까? 내 전화에서 포트를 터널링 할 때이 문제가 발생하여 마침내 연결 watch과 같은 명령을 사용하여 더미 명령을 생성하여 "사용"하도록했습니다 watch -n1 60 echo "wiiiii". 네트워크가 고장 나거나 사용하지 않으면 터널이 죽지 않습니다.
erm3nda 2019

답변:


280

autossh 가 필요한 것 같습니다 . ssh 터널을 모니터링하고 필요에 따라 다시 시작합니다. 우리는 몇 년 동안 그것을 사용했으며 잘 작동하는 것 같습니다.

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

-M 매개 변수에 대한 자세한 내용은 여기를 참조하십시오.


2
autossh의 경우 +1, 주석에서 말하는 것을 수행합니다. 또한 기능의 일부는 모든 종류의 시간 초과를 방지하기 위해 연결 유지 스타일 패킷을 보내는 것입니다.
akent

30
예제 터널을 autossh대답에 넣을 수 있습니까?
Ehtesh Choudhury

5
autossh -f -nNT -i ~/keypair.pem -R 2000:localhost:22 username@myoutsidebox.com autossh를 백그라운드에 넣을 수 있도록 원격 터미널을 만들지 않는 -nNT를 사용하여 설정하고 SSH의 .pem 파일을 사용하기위한 -i 옵션을 알 수 있습니다. 항상 연결을 열어 두려면 추가 설정을 수행하는 것이 좋습니다.
juckele

2
가치있는 것은 일반적으로 다음과 같은 -M매개 변수 를 생략하는 것이 좋습니다 . bugs.debian.org/cgi-bin/bugreport.cgi?bug=351162
rinogo

2
autossh -M 0 -o "ServerAliveInterval 10"-o "ServerAliveCountMax 2"-L 9999 : localhost : 19999 server@example.com
Luke Stanley

39

모든 상태 저장 방화벽은 일정 시간 동안 해당 연결에 대한 패킷을 보지 못한 후 연결을 잊어 버립니다 (연결을 닫지 않고 양쪽 끝이 종료 된 상태 테이블이 연결로 가득 차는 것을 방지하기 위해). 대부분의 TCP 구현은 상대방의 의견을 듣지 않고 오랜 시간이 지난 후 keepalive 패킷을 보냅니다 (2 시간은 공통 값). 그러나 keepalive 패킷을 보내기 전에 연결을 잊어 버리는 상태 저장 방화벽이 있으면 오래 지속되지만 유휴 연결이 끊어집니다.

이 경우 해결 방법은 연결이 유휴 상태가되는 것을 방지하는 것입니다. OpenSSH에는 ServerAliveInterval 이라는 옵션이 있습니다.이 옵션을 사용하면 연결이 너무 오래 유휴 상태가되는 것을 방지 할 수 있습니다 ( 상대적 으로 연결이 유휴 상태 일 때 피어가 더 빨리 사망 한시기를 감지 함).


지정된 간격은 초 단위이므로 약간의 미세 조정을 제공 할 수 있습니다. 상태 저장 방화벽에 5 분의 유휴 시간 제한이있는 경우 연결을 계속 유지하기에 60 초 또는 120 초로 충분합니다. 홈 라우터를 통해 내 ssh 세션을 열어 두는 방법 중 하나입니다.
Darren Hall

감사합니다. 그러나 주 (여기 낮은 순위 응답에서 superuser.com/a/146641/115515 당신이 ServerAliveInterval하지 ServerAliveCountMax를 지정하는 경우, 당신은 ssh를 의도적으로 빨리 당신이 원하는 것보다 분리 찾을 수 있음).
metamatt

4
@metamatt, 당신이 참조하는 낮은 순위의 답변은 정당한 이유로 낮은 순위입니다 : IT IS 잘못된.
Lambart

24

자신의 Mac 또는 Linux 시스템에서 ssh를 구성하여 3 분마다 서버 ssh를 활성 상태로 유지하십시오. 터미널을 열고 집에 보이지 않는 .ssh를 입력하십시오.

cd ~/.ssh/ 

그런 다음 1 줄 구성 파일을 작성하십시오.

echo "ServerAliveInterval 180" >> config

또한 다음을 추가해야합니다.

ServerAliveCountMax xxxx (high number)

기본값은 3이므로 ServerAliveInterval 180은 9 분 (ServerAliveInterval에서 지정한 3 분 간격 중 3 분) 후에 전송을 중지합니다.


2
구성 파일이 이미 있으면 명령을 사용하지 않는 것이 좋습니다. 리디렉션에 >>를 사용하는 것이 훨씬 좋습니다!
Peltier

ServerAliveInterval 180우리에게 6 분을 주나요? 직감은 내가 이것을 시도하게합니다 : 180/60 == 3. 그렇다면 ServerAliveInterval30 초의 배수로 작동합니까?
nemesisfixx

@mcnemesis : ServerAliveInterval 180은 3 분을 의미합니다. ServerAliveCountMax 기본값 3은 이러한 간격 중 3 개를 의미하므로 9 분입니다.
metamatt

2
ServerAliveCountMax를 언급 해 주셔서 감사합니다. ServerAliveCountMax없이 ServerAliveInterval을 지정하면 어떻게됩니까? 그러나 이전 의견과 마찬가지로 "다음에 보내기 중지"에 대한 계산이 잘못되었음을 알 수 있습니다. cd 및 echo 명령으로 해당 옵션을 적용하는 방법을 알려주지 않고 이러한 옵션에 대한 정보 만 제공하면이 답변이 더 잘 작동한다고 생각합니다. .
metamatt

20
ServerAliveCountMax를 "높은 수"로 설정하는 것은 의미가 없기 때문에 다운 보팅 ServerAliveCountMax는 포기하기 전에 "keepalive"메시지를 보내려고 시도하는 횟수를 지정합니다. 기본값은 3이므로 ServerAliveInterval 180의 경우 9 분 후에 서버가 응답하지 않으면 연결이 제대로 종료되지 않은 경우에만 전송을 중지합니다.
Lambart

22

다음 Bash 스크립트를 사용하여 이전 터널이 죽을 때 새로운 ssh 터널을 계속 생성했습니다. 스크립트를 사용하면 추가 패키지를 설치하지 않거나 컴파일러를 사용하지 않을 때 편리합니다.

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

연결을 자동으로 설정하려면 키 파일이 필요하지만 autossh도 마찬가지입니다.


2
autossh를 통해이 스크립트를 사용하는 이유를 추가해야합니까, 아니면이 방법이 더 쉬운 것입니까?
kyrias

4
ssh 자체가 멈 추면 도움이되지 않습니까?
nafg

1
서버에 설치할 수없는 경우 도움이됩니다. autossh는 사전 설치되어 있지 않으며 관료 주의적이며 때로는 매우 둔감합니다.
quarkex

예, 물건을 설치할 필요가 없습니다. 원격 컴퓨터에 액세스 할 수있는 유일한 방법 (재부팅 할 때 crontab을 실행하도록 설정)으로 1 년 동안이 방법을 사용했습니다. 결코 실패하지 않았으며, 더 중요한 것은 실패하지 않는 이유를 알고 있습니다.
sudo

16

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 년 1 월 업데이트 : 일부 배포판 (예 : Fedora 27)은 SELinux 정책을 사용하여 SSH를 사용하여 시스템 초기화를 방지 할 수 있습니다.이 경우 필요한 면제를 제공하기 위해 사용자 정의 정책을 작성해야합니다.


2
이것은 내 요지와 매우 비슷해 보입니다 : gist.github.com/guettli/… 피드백은 환영합니다!
guettli

systemd시스템에 탁월 합니다. 사용하는 경우 Restart=on-failureSSH 클라이언트를 수동으로 종료하면 SSH 클라이언트로 시스템이 다시 시작되지 않고 종료됩니다.
David Tonhofer

ExecStart예를 들어 ssh인수 목록 을 작성 하기 위해 인수로 제공된 (bash) 스크립트에서 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

10

ServerAliveCountMax를 모두 잘못 해석하고 있다고 확신합니다. 문서를 이해하면 연결이 종료되지 않고 응답하지 않을 수있는 서버 활성 메시지의 수입니다. 따라서 여기서 논의하는 것처럼 높은 값으로 설정하면 중단 된 연결이 감지되지 않고 종료되지 않습니다!

방화벽이 연결을 잊어 버린 경우 문제를 해결하려면 ServerAliveInterval을 설정하기 만하면 충분하며 ServerAliveCountMax를 낮게두면 원래 끝에서 오류를 감지하고 연결에 실패하면 종료됩니다.

원하는 것은 1) 정상적인 상황에서 연결이 영구적으로 열려 있고, 2) 연결 실패가 감지되고 시작 측이 실패하면 종료되고, 3) 매번 ssh 명령이 재발행 될 때입니다. 종료 (당신이 그렇게하는 방법은 플랫폼에 따라 다르며, Jawa가 제안한 "진정한"스크립트는 OS XI에서 실제로 시작된 항목을 설정하는 한 가지 방법입니다).


9

ServerAliveInterval만료 된 NAT 세션으로 터널 문제가 발생하는 경우 항상 SSH 옵션을 사용하십시오 .

연결이 완전히 다운되는 경우 항상 부활 방법을 사용하십시오. 여기에는 최소한 세 가지 옵션이 있습니다.

  • 오토시 프로그램
  • bash script ( while true do ssh ...; sleep 5; done)는 sleep 명령을 제거하지 않고 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'
    
  • Ubuntu의 upstart 스크립트 ( /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
    

또는 항상 두 가지 방법을 모두 사용하십시오.


1
모든 SSH 연결에 대해 원하지 않는 경우 인라인 옵션 +1
user1146334

"연결이 완전히 끊어진 경우"라고 쓴다. 이제 이해가 안됩니다. autossh가 어떤 문제를 스스로 해결합니까? 물론 몇 시간 동안 케이블을 뽑는 것과 같이 끊어진 연결을 처리해야한다고 생각했지만 그렇지 않습니까?
Mads Skjern

6

이 문제를 해결했습니다.

편집하다

~/.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.

15 초마다 서버를 핑하는 것이 자주 보입니다.
Lambart

@Lambart 그러나 연결이 실제로 비정상적이고 연결이 자주 끊기는 경우 적어도 연결이 끊어진 것을 감지하고 더 일찍 다시 시도 할 수있는 기회를 제공합니다.
binki

4

ExitOnForwardFailure yes다른 제안에 대한 좋은 보조입니다. 연결되었지만 포트 전달을 설정할 수없는 경우 마치 연결되지 않은 것처럼 쓸모가 없습니다.


이것은 매우 좋은 생각입니다. 이전 연결이 로컬 호스트보다 원격에서 이전에 시간 초과 된 것으로 인식되면 autossh도 쓸모가 없습니다.이 경우 로컬 호스트는 다시 연결을 시도하지만 포트가 여전히 열려 있기 때문에 전달을 설정할 수 없습니다.
Raúl Salinas-Monteagudo

1

SSH 터널을 장기간 유지 관리해야했습니다. 내 솔루션은 Linux 서버에서 실행 중이며 키 기반 인증을 사용하여 ssh를 다시 생성하는 작은 C 프로그램입니다.

교수형이 확실하지 않지만 시간 초과로 인해 터널이 죽었습니다.

respawner에 코드를 제공하고 싶지만 지금은 찾을 수 없습니다.


1

ssh 세션을 다시 시작하는 데 도움이되는 autossh와 같은 도구가 있지만 실제로 유용한 것은 'screen'명령을 실행하는 것입니다. 연결을 끊은 후에도 ssh 세션을 재개 할 수 있습니다. 연결 상태가 안정적이지 않은 경우 특히 유용합니다.

... k가 도움이된다면 이것이 '정답'이라고 표시하는 것을 잊지 마십시오! ;-)


7
...하지만 질문은 터미널 세션뿐만 아니라 SSH 터널을 열어 두는 방법에 관한 것이 었습니다. 화면은 훌륭합니다!
akent

나는 이미 스크린을 사용하고 있지만 내 문제를 해결하지 못합니다 :-/ 그래도 귀하의 답변에 감사드립니다.
Peltier

1

약간의 해킹이지만, 이것을 유지하기 위해 화면을 사용하고 싶습니다. 현재 몇 주 동안 실행 된 원격 전달 기능이 있습니다.

로컬로 시작하는 예 :

screen
ssh -R ......

원격 전달이 적용되고 원격 컴퓨터에 쉘이있는 경우 :

screen
Ctrl + a + d

이제 원격 순방향 중단이 발생했습니다. 요령은 양쪽 끝에서 화면을 실행하는 것입니다


1

암호 로그인을 사용하는 경우 매번 암호를 다시 입력해야하기 때문에이 문제가 발생했습니다. 배치 파일에 암호가 포함되지 않도록 텍스트 프롬프트와 함께 루프에서 sshpass를 사용했습니다.

다른 사람이 같은 문제가있는 경우이 주제에 대한 해결책을 공유하겠다고 생각했습니다.

#!/bin/bash
read -s -p "Password: " pass
while true
do
    sshpass -p "$pass" ssh user@address -p port
    sleep 1
done

0

이전 ISP와 비슷한 문제가있었습니다. 나에게 그것은 tcp 연결, 웹 사이트 방문 또는 메일 전송과 동일합니다.

해결책은 UDP를 통해 VPN 연결을 구성하는 것입니다 (OpenVPN을 사용하고있었습니다). 이 연결은 연결이 끊긴 원인에 대해 더 관대했습니다. 그런 다음이 연결을 통해 모든 서비스를 실행할 수 있습니다.

연결에 여전히 문제가있을 수 있지만 터널은 더 견딜 수 있으므로 모든 ssh 세션은 연결이 끊기는 대신 짧은 보류 상태를 느낄 것입니다.

이렇게하려면 자체 서버에서 설정할 수있는 온라인 VPN 서비스가 필요합니다.


0

으로 autossh우리의 요구를 (그것이 첫 번째 시도에서 서버에 연결할 수없는 경우이 오류가 존재)을 만족하지 못하는, 우리는 순수 bash는 응용 프로그램을 작성했습니다 : https://github.com/aktos-io/link- 서버

기본적으로 서버에서 NODE의 sshd 포트 (22)에 대한 역방향 터널을 만듭니다. 추가 포트 전달, 연결시 메일 보내기 등과 같은 다른 작업을 수행해야하는 경우 스크립트 on-connecton-disconnect폴더를 배치 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.