ssh는 모든 장치에서 작동하지만 일부 장치에서는 scp가 "연결이 닫혔습니다" 오류가 발생합니다.

ssh는 모든 장치에서 작동하지만 일부 장치에서는 scp가 "연결이 닫혔습니다" 오류가 발생합니다.

빠른 버전:

ssh& scp내 데스크탑과 노트북에서 작동합니다. 내 Android 휴대폰에서 termux는 ssh작동하지만 scp작동하지 않습니다. 이 경우 "연결이 닫혔습니다"라는 오류가 발생합니다.


확장 버전

원래 이 질문을 했을 때 Fedora Linux 상자에 연결되어 있는 동안 Android 휴대폰의 termux에서 scp를 실행하는 동안 이 문제가 발생했습니다. ssh이것저것 작업을 하다가 디버깅 정보를 많이 제공하고 있어서 헷갈립니다 . 나중에 문제가 termux와 전혀 관련이 없고 모든 것이 OpenSSH 버전과 관련이 있다는 것을 알게 되었기 때문에 더 나은 SEO 일치를 위해 관련 오류 메시지를 유지하면서 방대한 외부 정보 덤프를 정리하고 더 쉽게 액세스할 수 있도록 노력했습니다. .

장비:

  • 장치 A(컴퓨터): openssh.x86_64 8.7p1-3.fc35를 실행하는 Fedora 35
  • 장치 B(컴퓨터): openssh.x86_64 8.7p1-3.fc35를 실행하는 Fedora 35
  • 장치 C(전화): android의 termux(처음에는 openssh 버전, 아마도 v8.8 이상을 캡처하지 못했습니다)

컴퓨터 A와 B는 기본적으로 동일한 sshd_config파일을 갖고 있으며, 파일 내용은 기본적으로 3대의 컴퓨터 모두에서 동일합니다 ~/.ssh/config.

질문:

A->B, B->A, C->A 및 C->B 사이의 SSH 연결은 모두 잘 작동합니다. 나는 어느 컴퓨터에서나 내 전화기에 연결하는 데 관심이 없으며 SSHD를 구성한 적이 없으므로 해당 시나리오를 테스트하지 않았습니다.

그러나 ssh를 통해 scp를 실행하면 다음과 같은 상황이 발생합니다. A->B 및 B->A는 작동하지만 C->A 및 C->B는 다음 오류와 함께 실패합니다.

$ scp -rp "[email protected]:/home/desktop-user/Pictures/test.jpg" .
scp: Connection closed
 

디버그:

  • SSH 파일 권한, 소유권 ~/.ssh/config, 설정 등에 대한 광범위한 확인 명백한 문제는 없습니다.
  • A와 B에서 SELinux와 방화벽을 (일시적으로) 비활성화했지만 여전히 동일한 문제가 있습니다.
  • 기반으로이 게시물, 기본 이름을 사용하도록 사용자 정의 id_rsa(및 id_rsa.pub) 파일 이름을 바꾸고 해당 ~/.ssh/config정의를 편집했습니다. 잔돈을 유지해주세요.
  • C에서 파일을 받거나 가져오는 대신~에서원격으로 파일을 푸시/전송하려고 합니다.도착하다리모콘. 잔돈을 유지해주세요.
  • C부터 시작하여 모든 패키지가 최신 상태인지 확인합니다. 잔돈을 유지해주세요.
  • 자세한 디버깅 정보를 제공하기 위해 플래그를 scp사용하여 C에서 명령을 실행합니다 . -v해시 등을 편집한 후 추가했습니다.페이스트빈. 내가 본 가장 중요한 점은 키가 승인된 것 같지만 마지막 줄에 "debug1: 종료 상태 127"이라고 표시되어 있다는 것입니다. 온라인 결과는 scp호스트 시스템에 존재하지 않는 것으로 나타납니다. 하지만 제 경우에는 존재합니다. 그래서 여전히 변화가 없습니다.

호스트 SSHD 구성

마찬가지로 A와 B의 구성은 기본적으로 동일합니다.

# grep -Pv '^\s*(#|$)' /etc/ssh/sshd_config
Include /etc/ssh/sshd_config.d/*.conf
Port 22
Ciphers [email protected],aes256-ctr
LoginGraceTime 1m
PermitRootLogin no
MaxAuthTries 4
MaxSessions 6
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
UseDNS yes
AcceptEnv LANG LC_*
Subsystem   sftp    /usr/lib/openssh/sftp-server
Protocol 2
DenyUsers root docker-user
MACs [email protected],hmac-sha2-512,[email protected],hmac-sha2-256
KexAlgorithms diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256

답변1

익스프레스 버전(TL;DR)

고쳐 쓰다: 빨리 알고 싶고, 최소한의 내용이라도 읽고 싶은 분들을 위한 제품입니다.

알다:

  1. 이는 실제로 Termux와 관련이 없습니다. OpenSSH 8.8+를 사용하는 모든 Linux에 영향을 미칩니다. OpenSSH 8.7p1을 사용하는 Fedora 35에서도 이 문제가 발생했습니다.
  2. sftp긴급 상황에서는 작동 하지만 심볼릭 링크 복사를 다르게 처리하므로 scp대체용으로 스크립트에 넣지 마십시오. 를 사용하는 것이 더 좋습니다 rsync.

디렉터리를 원격에서 로컬로 반복적으로 복사합니다.

# deprecated / insecure (see CVE link below) but works
scp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
# secure / recommended by openssh - also works
rsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

로컬에서 원격으로 디렉터리를 반복적으로 복사합니다.

# deprecated / insecure (see CVE link below) but works
scp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
 
# secure / recommended by openssh - also works
rsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"

이는 다중 경로에도 적용됩니다.

# copy multiple paths
rsync -saLPz --port <port> -e ssh "<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>" "<user>@<host_ip>:<DST_PATH>"
 
# copy multiple paths from array
arrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");
rsync -saLPz -e ssh "${arrPaths[@]}" "<user>@<host_ip>:<DST_PATH>"

근본 원인

~ 후에많은온라인 사냥 나마침내답을 찾았습니다여기- 초기 수정 사항을 찾고 무슨 일이 있었는지 알려준 manjaro 포럼 사용자 zbe 및 canyue980에게 감사드립니다.

canyue980 인용:

도움을 주신 모든 분들께 감사드립니다! 방금 위 링크에서 해결책을 찾았습니다.

참고: OpenSSH 8.8부터 scp 유틸리티는 기본적으로 SFTP 프로토콜을 사용합니다. 레거시 SCP 프로토콜을 사용하려면 -O 옵션이 필요합니다.

-O 옵션을 사용하세요!

scp -O 파일 이름 대상 디렉터리

물론 아래와 같이 ~/.zshrc에 별칭을 추가할 수도 있습니다.

별칭 scp="scp -O"

실제로 내 명령은 다음으로 시작됩니다.

scp -rp -P 1234 "[email protected]:/home/desktop-user/Pictures/test.jpg" .

도착하다:

scp -rpO -P 1234 "[email protected]:/home/desktop-user/Pictures/test.jpg" .

그것은 챔피언처럼 작동합니다. 이것을 열어두고 다른 사람들에게 도움이 되기를 바랍니다.


-O의 보안 영향

사용하기에 안전한 의미 -O(예: "오", 예전과 마찬가지로 0이 아님):릴리즈 노트openssh 8.8의 경우 주요 위험은 다음과 같습니다.

이전 버전의 scp/rcp는 원격 셸을 통해 원격 파일 이름(예: "scp 호스트:* .")의 와일드카드 확장을 수행합니다. 이에 대한 부작용은 scp(1) 명령줄에 포함된 파일 이름에 쉘 메타 문자를 큰따옴표로 묶어야 한다는 것입니다. 그렇지 않으면 원격 측에서 쉘 명령으로 해석될 수 있습니다.

저는 개인적으로 이것이 이전 명령에 익숙하고 이를 수동으로 실행하거나 가정용 컴퓨터에서 신뢰할 수 있는 스크립트를 통해 실행하는 사람들에게는 큰 위험이라고 생각하지 않습니다. 그러나 위험 평가/사용 사례는 다양할 수 있습니다. 특히 확인되지 않거나 신뢰할 수 없는 스크립트를 사용하는 비즈니스 시스템 또는 설정의 경우 더욱 그렇습니다. 이건 일부의 경우인 것 같습니다RHEL 9는 scp 프로토콜을 더 이상 사용하지 않습니다., 인용하다:

SCP 프로토콜은 수십 년이 지났고 직접적인 해결책이 없는 여러 보안 위험과 문제가 있기 때문에 이렇게 변경했습니다. 새로운 문제가 자주 보고됩니다(CVE-2020-15778이 글을 쓰는 시점에서는 최신이지만 마지막이 될지 확신할 수 없습니다.) 프로토콜은 본질적으로 인증된 세션을 신뢰할 수 있기 때문에 이를 올바르게 수정하는 것은 매우 어렵습니다.

위의 릴리스 노트와 링크, 댓글에서아치스 위키, 완전히 사용하지 않으려는 의도인 것 같습니다.SCP(예: 프로토콜) 은 및 (아래 참조) sftp과 같은 대안을 지원합니다. rsync회사의 향후 계획이 무엇인지 모르겠습니다.scp 주문하다예, 특히 단기적으로는 그렇습니다. 하지만 향후에는 더 이상 사용되지 않을 가능성이 높습니다.


권장 대안

스크립트에서 삽입-교체로 sftp사용 하면 적어도 Fedora 35부터 시작해야 하는 호스트 변경이 필요하지 않으므로 삽입-교체가 더 쉬울 것입니다 .rsyncrsyncsftp

sftpsftp <user>@<host_ip>아래 명령은 다음을 사용하여 연결할 수 있는 한 작동합니다(이 방법으로 연결하면 "쉘" ssh에 들어가게 됩니다 . 종료하려면 를 사용하십시오 ). 그렇지 않으면 호스트 시스템에서 이를 활성화해야 할 수도 있습니다. Fedora 35의 경우 프로세스는 다음과 같습니다.sftpexit

  1. sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +'%F_%T').bak
  2. sudo sed -Ei 's~^(Subsystem[ \t]+sftp[ \t]+)(/usr/lib/openssh/sftp-server)~#\1\2\n\1internal-sftp~g' /etc/ssh/sshd_config
  3. sudo systemctl restart sshd

완료되면 다음과 같은 내용이 표시됩니다(예를 들어 sftp 서버 행은 주석 처리되고 그 자리에 Internal-sftp가 추가된 새 행이 추가되어야 합니다).

sudo grep Subsystem /etc/ssh/sshd_config
#Subsystem  sftp    /usr/lib/openssh/sftp-server
Subsystem   sftp    internal-sftp

보안을 강화해야 하는 경우 그룹 및 chroot를 사용하여 표시된 대로 이 작업을 제한할 수도 있습니다.여기그리고여기.

참고: scp기본적으로 심볼릭 링크의 내용은 대신 복사됩니다.~처럼심볼릭 링크. Rsync를 사용 -l하면 기호 링크로 복사 또는 -L기호 링크가 참조하는 항목 복사를 사용하여 이 동작을 제어할 수 있습니다 . 별도로 지정 하지 않는 한 (아카이브) 옵션 -a의 기본값은 입니다 . 심볼릭 링크를 링크로 복사합니다(예: 다음과 같은 항목을 가리킴).-l-Lsftp아니요복사됨), 이 글을 쓰는 시점에는 이 동작을 제어할 수 있는 옵션이 없습니다. -r옵션에 대한 문서와 해당 옵션 아래의 문서를 각각 보면 이를 확인할 수 있습니다 .man scpman sftp

~/.ssh/config다음은 모든 SSH를 수행하고 설정과 ID를 가져오는 거의 동일한 명령의 몇 가지 예입니다 .

디렉터리를 원격에서 로컬로 반복적으로 복사합니다.

scp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
rsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

로컬에서 원격으로 디렉터리를 반복적으로 복사합니다.

scp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
 
rsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"

SFTP 구문 수정

편집: 2022년 9월 13일: 오늘 다시 테스트하는 동안 내가 실행한 명령에 sftp오류가 있다는 사실이 확인되어 위의 명령에서 제외하고 몇 가지 면책조항을 추가했습니다. 나는 개인적으로 심볼릭 링크와 관련하여 복사를 처리하는 방법에 대해 위에서 언급한 차이점 때문에 sftp대체품으로 권장하지 않습니다 .scp

특히 스크립트에서 대체품으로 사용하는 데 관심이 있습니다. 대화형 모드만 필요하거나 이에 대한 "배치" 지침 파일을 만드는 것을 꺼리지 않거나 사용할 모든 컴퓨터에 sftp이미 해당 모드가 설치되어 있는 경우 여기까지 진행할 필요가 없을 것입니다. rsync내 다음 메모는 부분적으로 다음 내용을 기반으로 합니다.이 답변, 몇 가지 추가 테스트를 수행했습니다.

여기서 가장 큰 불만 sftp은 (다른 업로드 및 다운로드 구문을 사용하는 것 외에)문서화가 매우 열악함. 보기 man sftp, 문법이 기록되지 않습니다별말씀을요(이는 도구가할 수 있는비대화형으로 사용되는 경우 배치 및 대화형 모드에서의 사용은 문서화되어 있으며 해당 사용 사례에서는 제외됩니다(지원되는 동안은 문서화되지 않음). 매뉴얼 페이지는 일반적인 사용법의 예를 제공하지 않으며, 많은 GNU 도구와 같이 더 자세한 문서를 제공하는 웹사이트도 제공하지 않습니다. 그리고 sftp -h매뉴얼 페이지보다 적은 수를 제공합니다. 말 그대로 이런 검색엔진이나 사이트가 없었다면 아예 sftp옵션을 포기했을 것입니다 .

1. 로컬 풀(예: 로컬 터미널에서 원격에서 로컬로 파일 다운로드)

scp이는 위에서 언급한 차이점(예: 심볼릭 링크)과 약간 다른 구문을 제외하면 대부분 간단하며 다소 유사하게 작동합니다. 이러한 변형 중 하나는 대화형 프롬프트로 이어집니다.

# Download a single file with same name to current dir
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>"
# or
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" .
 
# Download a single file to name and path in "<DST_PATH>"
sftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"
 
# Download a folder and all of its contents,
# keep the same name as the remote and save to current dir
# note that any symlinks will copy only the symlink itself
# and NOT the data the link references
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" .
 
# Now if you omit "<DST_PATH>" entirely like you can with
# the single-file version (first command in this code-block)
# you instead drop to an interactive prompt and have to type
# type 'exit' to get back to your bash prompt
# e.g. AVOID THIS IN NON-INTERACTIVE SCRIPTS!!!
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>"
Connected to <host_ip>.
Changing to: <SRC_PATH>
sftp> 
sftp> exit
  
# Download a folder and all of its contents,
# to name and path in "<DST_PATH>"
# note that any symlinks will copy only the symlink itself
# and NOT the data the link references
sftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"

2. 로컬 푸시(예: 로컬 터미널에서 로컬에서 원격으로 파일 업로드)

첫째, 원래 답변처럼 매개변수를 반대로 바꾸려고 하면 연결 오류가 발생합니다. sftp업로드 구문이 다운로드 구문과 일치하지 않는 이유 는 무엇입니까 ? 당신의 추측은 나만큼 훌륭합니다. 나 자신도 이 방법의 열렬한 팬입니다. 그러나 시도해 보면 다음과 같은 일이 발생합니다(참고: 이 출력은 ssh가 올바르게 구성된 Fedora 35를 실행하는 두 시스템에서 나온 것이며 scp인증 rsync ... -e ssh메시지 없이 잘 작동합니다).

# single file
sftp -pC -P <port> test.txt "<user>@<host_ip>:<DST_PATH>"
ssh: Could not resolve hostname test.txt: Name or service not known
Connection closed.  
Connection closed

# dir
sftp -rpC -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"
ssh: Could not resolve <SRC_PATH>: Name or service not known
Connection closed.  
Connection closed

모든답변위에 링크했는데 올바른 방법은 다음과 같습니다

# push a single file from local to remote
sftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< 'put test.txt'
# or
echo 'put test.txt' | sftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>"

# push a entire dir (and its contents) from local to remote
# notice the inner single quotes to escape <SRC_PATH>
# for enclosing paths containing whitespace
sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< "put '<SRC_PATH>'"
# or
echo "put '<SRC_PATH>'" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"
# or
printf 'put "%s" "%s"\n' "<SRC_PATH>" "<DST_PATH>" | \
sftp -rpC -P <port> "<user>@<host_ip>"

예를 들어 다운로드에 비슷한 구문을 사용하는 스크립트를 찾았습니다.

# pull a entire dir (and its contents) from remote to local
# notice the inner single quotes to escape <SRC_PATH>
# for enclosing paths containing whitespace
printf 'get "%s" "%s"\n' "<SRC_PATH>" "<DST_PATH>" | \
sftp -rpC -P <port> "<user>@<host_ip>"

너무 혼란스럽지는 않지만 위의 모든 사항이 작동해야 합니다.

put여러 경로를 한 번에 복사하려면 배열을 사용할 수 있습니다(또는 각 명령을 별도의 줄에 나열하는 배치 파일을 만들고 sftpuse -b <batchfile>옵션을 전달할 수 있습니다).

# copy multiple paths from array
arrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");
printf 'put %s\n' "${arrPaths[@]}" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"

2022년 10월 10일에 업데이트되었습니다.공백이 포함된 복사본에 몇 가지 문제가 발생한 후 옵션을 rsync사용하도록 명령을 업데이트했습니다 (-s이 답변)

그러나 나는 rsync가 공백 처리 scp와 다르며 sftp(공백 처리 측면에서) scp내부 따옴표가 포함된 경로에 대해서는 항상 괜찮다는 것을 알았습니다.

scp -rp "remoteuser@remotehost:'/tmp/rsync-test/stuff from server/the data.txt'" "."

그러나 에서 이 작업을 수행하면 rsync오류가 발생합니다.

$ rsync -saXULz --progress -e ssh \
  "remoteuser@remotehost:'/tmp/rsync-test/stuff from server/the data.txt'" "."
 
receiving incremental file list
rsync: [sender] change_dir "/home/remoteuser/'/tmp/rsync-test/stuff from server" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1839) [Receiver=3.2.5]
rsync: [Receiver] write error: Broken pipe (32)

이 문제를 해결하는 것은 매우 간단하지만 scp저처럼 내부 인용 경로 구문을 사용하는 데 익숙하다면 직관적이지 않을 수 있습니다. -s내부 인용을 사용하고 제거하면 됩니다. rsync그것을 처리할 수 있을 만큼 똑똑하면 실제로 작동합니다.

따라서 위의 잘못된 명령을 다음과 같이 변경하면 됩니다.

$ rsync -saXULz --progress -e ssh \
  "remoteuser@remotehost:/tmp/rsync-test/stuff from server/the data.txt" "."

모든 것이 잘 작동해야 합니다( scp모든 것이 동일한 경로에서 잘 작동한다고 가정).

관련 정보