VSCODE ssh 연결 실패 해결방법(could not establish connection to “tmp”)

VS Code Remote-SSH로 원격 서버에 붙으려 하면 “Could not establish connection to …”와 함께 “프로세스에서 없는 파이프에 쓰려고 했습니다”(Windows의 ERROR_PIPE_NOT_CONNECTED)가 뜨는 경우가 있다. SSH 자식 프로세스가 이미 죽어 파이프에 쓸 대상이 없다는 결과만 보여줄 뿐 왜 죽었는지는 알려주지 않아, “Remote-SSH: Show Log”로 별도 확인이 필요하다. 이 글에서는 흔한 원인들을 정리하고, 재현 가능한 것은 실제 SSH 세션으로 직접 만들어 확인한다.

핵심 개념: 연결 과정과 실패 지점

Remote-SSH 연결은 세 단계로 나뉘고, “파이프에 쓸 수 없다”는 이 중 어디서든 나올 수 있는 공통 증상이다.

단계하는 일실패 시 로그 위치
1. SSH 트랜스포트일반 ssh user@host와 동일한 인증/연결known_hosts, 키 권한 문제
2. VS Code Server 설치원격에 스크립트를 실행해 ~/.vscode-server에 Node.js 기반 서버 다운로드/설치설치 스크립트 stdout 파싱 실패
3. 서버 기동포트 바인딩, extension host 구동서버 프로세스 크래시

실전: 원인별 재현

셸 시작 스크립트가 출력을 오염시키는 경우

2단계 설치 스크립트는 비대화형 SSH stdout에서 특정 마커를 찾아 진행 상황을 판단하는데, ~/.bashrc의 대화형 가드(case $- in *i*) ;; *) return;; esac)보다 앞에 무조건 실행되는 echo(conda 배너 등)가 있으면 그 출력이 섞여 들어간다.

# 정상 상태: 비대화형 ssh 명령 출력에 잡음 없음
$ ssh testhost 'echo MARKER_START; echo MARKER_END'
MARKER_START
MARKER_END

# ~/.bashrc 맨 위(가드보다 앞)에 echo 한 줄만 추가한 뒤 동일 명령 재실행
$ ssh testhost 'echo MARKER_START; echo MARKER_END'
Welcome noble, have a nice day
MARKER_START
MARKER_END

GitHub 이슈의 WARN: $PLATFORM is undefined in installation script output도 같은 패턴이다 — 설치 스크립트가 배너 텍스트를 만나 파싱에 실패한다.

known_hosts 항목 충돌

서버 재설치나 IP 재사용(VM/클라우드 인스턴스 재발급 등) 환경에서는 저장된 예전 호스트 키와 실제 키가 달라 트랜스포트 단계부터 막힌다.

$ ssh testhost true
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
...
Offending ECDSA key in /home/noble/.ssh/known_hosts:9
  remove with:
  ssh-keygen -f '/home/noble/.ssh/known_hosts' -R '192.168.0.42'
Host key verification failed.

메시지의 ssh-keygen -R을 그대로 실행하면 해당 항목만 제거된다. VS Code는 이 프롬프트를 보여주지 못하고 그냥 연결 실패로 처리해 증상만으로는 원인을 짐작하기 어렵다.

ControlMaster 소켓이 죽은 채로 남는 경우

ControlPersist를 쓰는 환경에서 마스터 연결이 비정상 종료되면 소켓 파일만 남는다. 시스템 ssh는 이를 감지해 새 연결로 폴백하지만, VS Code의 로컬 프록시 프로세스는 이런 복구 로직이 없어 같은 증상으로 이어질 수 있다.

$ kill -9 <마스터 프로세스 PID>   # 비정상 종료 재현
$ ssh -o ControlPath=~/.ssh/sockets/testhost testhost 'echo test'
Control socket connect(~/.ssh/sockets/testhost): Connection refused
test

시스템 ssh는 경고만 찍고 정상 실행되지만, 죽은 소켓 파일은 rm ~/.ssh/sockets/*로 따로 정리해야 한다.

주의사항

  • 먼저 “Remote-SSH: Show Log” 명령으로 실제 원인이 1(트랜스포트)/2(설치)/3(기동) 중 어느 단계인지부터 확인할 것. 원인을 모른 채 서버 재설치나 known_hosts 삭제부터 시도하면 헛수고가 될 수 있다.
  • .bashrc/.zshrc에 배너·환영 메시지·conda/nvm 자동 출력 등을 넣을 때는 반드시 대화형 셸 가드 아래에 두고, 원격 자동화 스크립트(SSH 비대화형 명령, rsync, scp 등) 전부가 이 출력에 영향받는다는 점을 함께 고려한다.
  • known_hosts 충돌은 ssh-keygen -R로 해당 항목만 지우고, known_hosts 파일 전체를 삭제하지 않는다 — 다른 호스트 키까지 다 날아가 매번 재확인 프롬프트가 뜬다.
  • “Remote-SSH: Uninstall VS Code Server” 실행 후에도 원격의 ~/.vscode-server가 완전히 안 지워지는 경우가 있으니, 안 되면 SSH로 직접 접속해 해당 디렉토리를 지우고 재연결한다.
  • Windows에서 .pem/개인키 파일 권한이 너무 열려 있으면(상속된 그룹/기타 권한) Permission denied (publickey)로 실패한다. icacls로 현재 사용자에게만 읽기 권한을 부여해야 한다.

마무리

“Could not establish connection”은 증상일 뿐 원인이 아니다. 로그로 단계를 좁힌 뒤 맞는 조치를 적용하는 순서로 접근하면 삽질을 줄일 수 있다.

참고

답글 남기기