ssh: connect to host port 22: Connection refused 해결: 우분투 24.04 SSH 연결 거부 원인별 점검
이 글의 핵심
SSH 접속 오류는 메시지마다 실패한 지점이 다릅니다. Connection refused는 서버까지 도달했지만 22번 포트에서 듣는 프로세스가 없거나 REJECT로 거절된 것이고, Connection timed out은 중간 어딘가에서 패킷이 버려진 것이며, Permission denied (publickey)는 연결 자체는 성공하고 인증에서 막힌 것입니다. 이 글은 우분투 24.04 서버를 기준으로 메시지를 먼저 구분한 뒤, openssh-server 미설치, 22.10부터 바뀐 ssh.socket 방식의 포트 변경, ufw, WSL2·VM NAT, 클라우드 보안 그룹, fail2ban, kex_exchange_identification 오류, 호스트 키 변경 경고까지 원인별 확인 방법과 해결 명령을 정리합니다.
SSH 접속이 안 될 때 터미널에 찍히는 메시지는 몇 가지로 정해져 있습니다. 문제는 이 메시지들이 비슷해 보여서 “SSH가 안 된다”로 뭉뚱그려 검색하게 된다는 점입니다. 실제로는 메시지마다 실패한 위치가 달라서, 메시지를 정확히 읽기만 해도 점검할 범위가 절반 이하로 줄어듭니다. 서버의 sshd 설정을 몇 번씩 고쳤는데 원인은 클라우드 보안 그룹이었다거나, 방화벽을 다 열었는데 원인은 sshd가 설치조차 되어 있지 않았던 것이라거나 하는 헛걸음은 대부분 메시지를 구분하지 않아서 생깁니다.
기준 환경: 서버는 우분투 24.04 LTS(OpenSSH 9.6 계열, systemd), 클라이언트는 윈도우 10/11 내장 OpenSSH, macOS 터미널, 리눅스 중 무엇이든 됩니다. 우분투 22.04 이하 서버는 SSH가 소켓 활성화 방식이 아니므로 포트 변경 부분만 다르고, 나머지 점검 순서는 같습니다. 명령에 나오는 203.0.113.10은 예시 주소이고, 실제 서버 주소로 바꿔서 실행합니다.
에러 메시지별로 실패 지점이 다르다
SSH 연결은 TCP 연결 → SSH 버전 문자열 교환과 키 교환 → 사용자 인증 순으로 진행됩니다. 아래 메시지들은 각각 이 중 어디서 끊겼는지를 알려 줍니다.
Connection refused: 서버까지는 갔다
ssh: connect to host 203.0.113.10 port 22: Connection refused
클라이언트가 보낸 TCP SYN 패킷에 대해 상대가 RST(연결 재설정) 패킷으로 응답했다는 뜻입니다. 일반적으로 RST는 그 주소의 운영체제가 “이 포트에서 듣고 있는 프로그램이 없다”고 직접 대답할 때 나옵니다. 즉 네트워크 경로와 서버 OS는 살아 있고, 22번 포트에 sshd가 없다는 신호입니다. 예외로, 방화벽이 패킷을 조용히 버리는 대신 REJECT 규칙으로 거절하면(예: --reject-with tcp-reset, 또는 ICMP port unreachable로 응답하면) 같은 메시지가 나옵니다. fail2ban의 기본 차단 방식이 이런 REJECT 계열이라 차단당했을 때 refused가 보이는 경우가 있습니다.
로컬에서 아무것도 듣고 있지 않은 포트로 접속해 보면 이 메시지를 그대로 재현할 수 있습니다. 아래는 윈도우 11 내장 OpenSSH로 실행한 실제 출력입니다.
PS C:\Users\me> ssh -V
OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2
PS C:\Users\me> ssh -p 2222 127.0.0.1
ssh: connect to host 127.0.0.1 port 2222: Connection refused
Connection timed out: 응답 자체가 없었다
ssh: connect to host 203.0.113.10 port 22: Connection timed out
SYN을 보냈는데 아무 응답(SYN-ACK도 RST도)을 받지 못한 채 시간이 지났다는 뜻입니다. 중간 어딘가에서 패킷이 조용히 버려진 것입니다. 원인 후보는 서버의 방화벽(ufw는 기본적으로 들어오는 패킷을 DROP합니다), 클라우드 보안 그룹, 공유기 포트 포워딩 누락, 출발지 네트워크의 아웃바운드 차단, 아예 잘못된 IP나 꺼진 서버입니다. 아래는 응답하지 않는 주소로 접속을 시도한 실제 출력입니다. ConnectTimeout을 주지 않으면 OS 기본값만큼 기다리므로 수십 초에서 2분 가까이 멈춰 있게 됩니다.
$ ssh -o ConnectTimeout=3 -p 22 10.255.255.1
ssh: connect to host 10.255.255.1 port 22: Connection timed out
refused와 timed out의 차이는 점검 순서를 완전히 바꿉니다. refused라면 서버 안쪽(sshd가 떠 있는지, 어느 포트에서 듣는지)부터 보고, timed out이라면 서버 바깥쪽(방화벽, 보안 그룹, 라우팅)부터 봅니다. timed out인데 sshd_config를 고치는 것은 대개 시간 낭비입니다.
No route to host: 경로나 호스트를 찾지 못했다
ssh: connect to host 192.168.0.50 port 22: No route to host
클라이언트 OS가 그 주소로 가는 경로가 없다고 판단했거나, 중간 라우터 또는 대상 쪽에서 ICMP host unreachable 계열 응답이 돌아온 경우입니다. 같은 LAN 안이라면 대상 기기가 꺼져 있거나 IP가 바뀌어 ARP 응답이 없을 때 흔히 나옵니다. 일부 배포판의 방화벽(firewalld 기본 규칙 등)은 거절 시 icmp-host-prohibited를 보내기 때문에 이 메시지가 나오기도 합니다. 우선 ping과 ip neigh(맥은 arp -a)로 그 IP에 실제로 기기가 있는지 확인하고, DHCP로 IP가 바뀌었을 가능성을 먼저 의심합니다. 서버 IP를 고정하는 방법은 우분투 고정 IP 설정 글에서 다룹니다.
Permission denied (publickey): 연결은 성공했다
user@203.0.113.10: Permission denied (publickey).
이 메시지가 보인다면 TCP 연결, SSH 버전 교환, 키 교환까지 모두 성공한 것입니다. 네트워크와 방화벽은 문제가 없고, 사용자 이름이나 키, 서버의 authorized_keys, 비밀번호 로그인 허용 여부 같은 인증 설정을 봐야 합니다. 이 글의 범위 밖이라 자세한 내용은 Permission denied (publickey) 해결 글을 참고하면 됩니다. 괄호 안 목록(publickey,password 등)은 서버가 허용하는 인증 방식이므로, password가 빠져 있다면 서버에서 비밀번호 로그인이 꺼져 있다는 뜻입니다.
어느 메시지인지 애매하다면 -v 옵션으로 상세 로그를 봅니다. debug1: Connecting to ... 다음 줄에서 멈추면 TCP 단계, Local version string 이후에서 끊기면 버전 교환 단계, Authentications that can continue 이후라면 인증 단계입니다.
ssh -v user@203.0.113.10
서버에 openssh-server가 없다
refused의 가장 흔한 원인입니다. 우분투 데스크톱은 SSH 서버를 기본으로 설치하지 않습니다. 우분투 서버도 설치 과정에서 “Install OpenSSH server” 항목을 체크하지 않았다면 없습니다. 클라이언트(ssh 명령)는 들어 있기 때문에 “ssh가 있으니 서버도 있겠지”라고 착각하기 쉽습니다.
서버 콘솔(모니터를 직접 연결하거나 클라우드 웹 콘솔, VM 창)에서 확인합니다.
dpkg -l openssh-server
no packages found matching openssh-server가 나오거나 첫 열이 ii가 아니면 설치되지 않은 것입니다. 설치합니다.
sudo apt update
sudo apt install openssh-server
설치하면 소켓이 자동으로 활성화됩니다. 상태를 확인할 때는 서비스 이름이 sshd가 아니라 ssh라는 점에 주의합니다. 다른 배포판 문서를 보고 systemctl status sshd를 치면 환경에 따라 Unit sshd.service could not be found가 나와서 설치가 안 된 것처럼 보일 수 있습니다.
systemctl status ssh.socket
systemctl status ssh
우분투 24.04의 ssh.socket: 서비스가 꺼져 보이는 이유
우분투 22.10부터 SSH 서버는 systemd 소켓 활성화 방식으로 바뀌었고, 24.04 LTS도 이 방식이 기본입니다. 이 변화를 모르면 두 가지 혼란이 생깁니다.
첫째, systemctl status ssh가 inactive (dead)로 나옵니다. 이 방식에서는 ssh.socket 유닛이 22번 포트를 열어 두고 기다리다가 첫 연결이 들어오면 그때 ssh.service(sshd 프로세스)를 띄웁니다. 그래서 접속이 없는 동안에는 서비스가 꺼져 있는 게 정상이고, 상태 출력에 TriggeredBy: ● ssh.socket이 보입니다. 이 상태에서 “서비스가 죽어 있다”고 판단해 ssh.service만 enable하는 식으로 손을 대면 구성이 꼬일 수 있습니다. 확인 대상은 ssh.socket입니다.
둘째, 더 자주 문제를 일으키는 부분인데, /etc/ssh/sshd_config의 Port만 바꾸고 systemctl restart ssh를 하면 포트가 바뀌지 않습니다. 실제로 포트를 여는 것은 sshd가 아니라 systemd이기 때문입니다. 우분투는 sshd_config의 Port와 ListenAddress 값을 읽어 ssh.socket의 설정으로 옮겨 주는 생성기(generator)를 두고 있는데, 이 생성기는 systemctl daemon-reload 때 실행됩니다. 따라서 포트를 바꾼 뒤에는 아래 순서가 필요합니다.
# 1) 방화벽에서 새 포트를 먼저 연다 (ufw를 쓰는 경우)
sudo ufw allow 2222/tcp
# 2) 포트 변경: sshd_config 또는 sshd_config.d 아래 파일
sudo nano /etc/ssh/sshd_config # Port 2222
# 3) 설정 문법 검사
sudo sshd -t
# 4) 생성기를 다시 돌리고 소켓을 재시작
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
# 5) 새 포트에서 듣는지 확인
sudo ss -tlnp | grep -E ':22\b|:2222\b'
이 과정을 빼먹으면 서버는 계속 22번에서 듣고 있는데 클라이언트는 ssh -p 2222로 접속해 refused를 받게 됩니다. 반대로 22.04 서버에서 하던 대로 했는데 “포트를 바꿨더니 refused가 난다”는 상황도 같은 원인입니다. 4번 단계를 실행한 뒤에는 기존 SSH 세션을 끊지 말고 새 터미널에서 새 포트 접속을 먼저 확인합니다. 잘못되면 기존 세션에서 되돌릴 수 있기 때문입니다.
소켓 활성화 방식이 맞지 않는 경우(예: 기존 자동화 스크립트가 ssh.service 기준으로 짜여 있는 경우) 예전 방식으로 되돌릴 수도 있습니다. 기본 절차는 다음과 같지만, 우분투 버전에 따라 추가로 정리해야 할 drop-in 파일이 있을 수 있으므로 해당 버전의 릴리스 노트를 함께 확인하는 것이 안전합니다.
sudo systemctl disable --now ssh.socket
sudo systemctl enable --now ssh.service
실제로 듣고 있는지 ss로 확인
설치와 설정을 마쳤다면 서버 안에서 어느 주소, 어느 포트로 듣고 있는지 직접 확인합니다. 추측보다 이 한 줄이 빠릅니다.
sudo ss -tlnp
-t는 TCP, -l은 듣고 있는(LISTEN) 소켓만, -n은 포트 번호를 이름으로 바꾸지 않음, -p는 프로세스 표시입니다. 출력에서 확인할 것은 세 가지입니다.
0.0.0.0:22또는[::]:22, 혹은*:22처럼 모든 주소에서 듣고 있는지.127.0.0.1:22만 보이면 서버 자신에게서만 접속을 받는 상태이므로,sshd_config에ListenAddress 127.0.0.1같은 줄이 있는지 확인합니다.- 포트 번호가 클라이언트가 접속하려는 번호와 같은지.
- 프로세스 칸. 소켓 활성화 상태라면
users:(("systemd",pid=1,...))처럼 systemd가 포트를 쥐고 있는 것으로 나오는 게 정상입니다. sshd가 아니라 systemd가 보인다고 이상한 것이 아닙니다.
서버 자신에게 접속해 보는 것도 좋은 분리 방법입니다. ssh localhost가 되는데 외부에서 안 된다면 sshd는 정상이고 문제는 방화벽이나 네트워크 쪽입니다. ssh localhost도 refused라면 서버 내부 문제입니다.
ufw 방화벽: 켜 놓고 22번을 안 열었다
우분투의 ufw는 설치 직후 비활성 상태라 기본으로는 아무것도 막지 않습니다. 문제는 보안 가이드를 따라 sudo ufw enable을 한 뒤입니다. ufw는 켜는 순간 들어오는 연결을 기본 거부(deny)하고, 이때 패킷을 조용히 버리기 때문에 클라이언트에서는 refused가 아니라 timed out이 납니다.
sudo ufw status verbose
Status: active인데 목록에 22(또는 OpenSSH)가 없다면 열어 줍니다. 우분투에는 openssh-server가 등록해 둔 앱 프로필이 있어서 이름으로 열 수 있습니다.
sudo ufw allow OpenSSH # 22/tcp
# 또는 포트를 직접 지정
sudo ufw allow 22/tcp
# 특정 대역에서만 허용하려면
sudo ufw allow from 192.168.0.0/24 to any port 22 proto tcp
원격으로 접속한 상태에서 ufw enable을 실행하면 ufw가 “기존 SSH 연결이 끊길 수 있다”고 경고합니다. 이 경고를 넘기기 전에 반드시 ufw allow OpenSSH를 먼저 해 둬야 합니다. 순서를 거꾸로 하면 지금 세션은 유지되더라도 다음 접속부터 막혀서, 콘솔 접근이 없는 원격 서버라면 복구가 어려워집니다. 포트를 2222로 바꿨다면 OpenSSH 프로필은 22번만 열기 때문에 2222/tcp를 별도로 열어야 합니다.
ufw 외에 iptables나 nftables 규칙을 직접 쓰는 서버라면 sudo nft list ruleset 또는 sudo iptables -L -n -v로 22번 관련 규칙과 패킷 카운터를 확인합니다. DROP 규칙의 카운터가 접속 시도 때마다 올라간다면 거기서 막히고 있는 것입니다.
클라우드 보안 그룹과 공유기: 서버 밖에서 막히는 경우
서버 안에서 ss도 정상이고 ufw도 열려 있는데 외부에서 timed out이라면, 패킷이 서버에 도착하기 전에 버려지고 있습니다.
클라우드 VM(AWS EC2, GCP, Azure, 오라클 클라우드, 국내 클라우드 등)은 OS 바깥에 별도의 방화벽 계층이 있습니다. AWS는 보안 그룹과 네트워크 ACL, GCP는 VPC 방화벽 규칙, 오라클 클라우드는 보안 목록(Security List)과 NSG입니다. 여기서 인바운드 TCP 22를 허용하지 않으면 OS 설정과 무관하게 timed out이 납니다. 소스를 0.0.0.0/0으로 열면 전 세계에서 무작위 접속 시도가 들어오므로, 가능하면 내 공인 IP 하나(/32)로 제한합니다. 집이나 사무실의 공인 IP가 바뀌면 어제까지 되던 접속이 갑자기 timed out이 되는 원인이 되기도 합니다. 오라클 클라우드의 우분투 이미지는 클라우드 쪽 규칙과 별개로 OS 안에도 iptables 규칙이 미리 들어 있는 경우가 있어서, 두 군데를 모두 확인해야 합니다.
집에 둔 서버를 외부에서 접속하려면 공유기에서 외부 포트를 서버의 내부 IP:22로 넘겨 주는 포트 포워딩이 필요합니다. 이때 주의할 점이 두 가지 있습니다. 하나는 서버 IP가 DHCP로 바뀌면 포워딩 대상이 엇나간다는 것이고, 다른 하나는 집 안 네트워크에서 공유기의 공인 IP로 접속하는 경우 공유기가 NAT 루프백(헤어핀)을 지원하지 않으면 실패한다는 것입니다. 외부 접속 테스트는 휴대폰 테더링처럼 실제로 바깥에 있는 네트워크에서 해야 정확합니다. 또 일부 통신사 회선은 22번 같은 포트를 막거나 공인 IP 대신 사설 IP(CGNAT)를 주는 경우가 있어서, 그럴 때는 포트 포워딩만으로는 외부 접속이 되지 않습니다.
클라이언트 쪽에서 포트까지 TCP가 열리는지만 빠르게 확인하는 방법도 알아 두면 좋습니다. SSH 설정과 무관하게 순수하게 TCP 연결만 시험합니다.
# 리눅스, macOS
nc -vz 203.0.113.10 22
# 윈도우 PowerShell
Test-NetConnection 203.0.113.10 -Port 22
nc가 succeeded, Test-NetConnection이 TcpTestSucceeded : True라면 TCP 단계는 통과하므로, 이후 문제는 SSH 프로토콜이나 인증 쪽입니다.
WSL2와 가상 머신: NAT 뒤에 있는 우분투
WSL2나 VirtualBox·VMware의 NAT 모드에서 돌리는 우분투는 호스트와 다른 가상 네트워크에 있습니다. 그래서 “호스트에서는 되는데 같은 LAN의 다른 PC에서는 안 된다”거나 “VM 안에서 ip a로 본 주소로 접속이 안 된다”는 일이 생깁니다.
WSL2의 기본 네트워크 모드는 NAT입니다. 윈도우 자기 자신에서 ssh -p 22 user@localhost로 접속하는 것은 WSL의 localhost 포워딩 덕분에 대체로 동작하지만, 다른 PC에서 윈도우 IP로 접속하면 WSL까지 전달되지 않습니다. 해결 방법은 두 가지입니다.
- mirrored 네트워크 모드: 윈도우 11 22H2 이상에서
%UserProfile%\.wslconfig에 아래를 넣고wsl --shutdown후 다시 시작하면 WSL이 윈도우와 같은 네트워크 인터페이스를 공유합니다. 이 경우에도 윈도우 방화벽(Hyper-V 방화벽 포함)에서 인바운드가 허용되어야 합니다.
[wsl2]
networkingMode=mirrored
- portproxy: NAT 모드를 유지하면서 윈도우가 받은 연결을 WSL 내부 IP로 넘깁니다. WSL 내부 IP는 재시작할 때마다 바뀔 수 있어서 매번 갱신해야 한다는 단점이 있습니다. 관리자 권한 PowerShell에서 실행합니다.
wsl hostname -I # WSL 내부 IP 확인, 예: 172.25.160.2
netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=22 connectaddress=172.25.160.2
New-NetFirewallRule -DisplayName "WSL SSH 2222" -Direction Inbound -Protocol TCP -LocalPort 2222 -Action Allow
또 WSL 안에서 openssh-server를 설치했는데 refused가 난다면 systemd가 켜져 있는지 확인합니다. 최근 wsl --install로 만든 우분투는 systemd가 기본으로 켜져 있지만, 오래된 설치본은 /etc/wsl.conf에 [boot] systemd=true가 없어 소켓이 올라오지 않을 수 있습니다. WSL 네트워크 설정은 WSL2 우분투 설치 글에서 더 자세히 다룹니다.
VirtualBox의 NAT 모드라면 VM 설정 → 네트워크 → 고급 → 포트 포워딩에서 호스트 포트 2222를 게스트 포트 22로 연결하고, 호스트에서 ssh -p 2222 user@127.0.0.1로 접속합니다. 게스트 안에서 본 10.0.2.15 같은 주소는 호스트에서 직접 접근할 수 없는 주소라서 그대로 접속하면 실패합니다. 같은 LAN의 다른 기기에서도 접속하려면 어댑터를 브리지 모드로 바꿔 VM이 공유기에서 직접 IP를 받게 하는 편이 단순합니다.
fail2ban에 차단당했을 때
어제까지 잘 되던 접속이 비밀번호를 몇 번 틀린 직후부터, 혹은 배포 스크립트가 여러 번 재시도한 직후부터 refused나 timed out으로 바뀌었다면 fail2ban 같은 침입 차단 도구를 의심합니다. fail2ban은 우분투 기본 설치에 포함되어 있지 않지만, 서버 보안 가이드에서 거의 항상 설치를 권하기 때문에 운영 서버에는 깔려 있는 경우가 많습니다. 기본 sshd jail은 일정 시간 안에 인증 실패가 여러 번 쌓이면 그 IP를 일정 시간 차단합니다. 차단 방식이 REJECT 계열이면 refused로, DROP 계열이면 timed out으로 보이므로 메시지만으로는 구분이 안 됩니다. 판단 근거는 “다른 IP(예: 휴대폰 테더링)에서는 된다”는 사실입니다.
다른 경로(콘솔, 다른 IP)로 서버에 들어가서 확인하고 풀어 줍니다.
sudo fail2ban-client status sshd
# Banned IP list 에 내 공인 IP가 있는지 확인
sudo fail2ban-client set sshd unbanip 198.51.100.7
자주 차단된다면 원인부터 고칩니다. 키 인증이 실패하면서 여러 키를 순서대로 시도하는 것도 실패 횟수로 쌓일 수 있으므로, ~/.ssh/config에 IdentitiesOnly yes와 사용할 키를 지정해 두면 불필요한 실패가 줄어듭니다. 사무실 IP처럼 신뢰하는 주소는 /etc/fail2ban/jail.local의 ignoreip에 넣어 차단 대상에서 뺄 수 있습니다.
kex_exchange_identification: TCP는 붙었는데 바로 끊길 때
kex_exchange_identification: read: Connection reset by peer
Connection reset by 203.0.113.10 port 22
또는
kex_exchange_identification: Connection closed by remote host
Connection closed by 203.0.113.10 port 22
이 메시지는 refused와 다릅니다. TCP 연결은 성공했지만, SSH가 첫 단계로 주고받는 버전 문자열(SSH-2.0-OpenSSH_...)을 받기도 전에 상대가 연결을 끊었다는 뜻입니다. 즉 포트는 열려 있는데 그 뒤의 무엇인가가 대화를 거부한 것입니다. 주요 원인은 다음과 같습니다.
- MaxStartups 초과: sshd는 인증이 끝나지 않은 동시 연결 수가 많아지면 새 연결을 확률적으로 끊습니다. 기본값은
10:30:100으로, 인증 대기 연결이 10개를 넘으면 30% 확률로 끊기 시작해 100개에서는 모두 끊습니다. 인터넷에 22번이 열린 서버는 무작위 공격 시도가 많아서 이 한도에 걸릴 수 있고, Ansible처럼 수십 개 연결을 동시에 여는 도구도 원인이 됩니다. 서버 로그(sudo journalctl -u ssh)에drop connection #... from ... past MaxStartups같은 줄이 있다면 이 경우입니다. - sshd 설정 오류나 호스트 키 문제: sshd가 설정 문법 오류나 호스트 키 파일 권한 문제로 연결을 처리하지 못하면 연결이 곧바로 닫힐 수 있습니다. 소켓 활성화 구성에서는 포트를 systemd가 열고 있으므로 TCP 연결 자체는 성공하고, 그 뒤 sshd가 정상적으로 응답하지 못해 끊기는 형태가 될 수 있습니다.
sudo sshd -t로 문법을 검사하고,journalctl -u ssh에서 오류를 확인합니다. - 중간 장비나 다른 프로그램: 포트 포워딩이 SSH가 아닌 다른 서비스로 향하고 있거나, 회사 네트워크의 보안 장비가 SSH 트래픽을 끊는 경우입니다.
nc 203.0.113.10 22로 접속했을 때SSH-2.0-OpenSSH_9.6p1 Ubuntu-...같은 배너가 한 줄 돌아오는지 보면, 정말 sshd가 그 포트 뒤에 있는지 확인할 수 있습니다.
참고로 클라이언트 OS와 OpenSSH 버전에 따라 같은 상황이 조금 다른 문구로 찍힙니다. 윈도우 11 내장 OpenSSH 9.5에서, 연결을 받자마자 닫아 버리는 간단한 테스트 서버에 접속했을 때의 실제 출력은 아래와 같았습니다. 리눅스에서 흔히 검색되는 Connection reset by peer/Connection closed by remote host와 문구는 달라도 같은 단계(버전 교환 전)에서 끊긴 것입니다.
kex_exchange_identification: read: Connection aborted
banner exchange: Connection to 127.0.0.1 port 2300: Connection aborted
REMOTE HOST IDENTIFICATION HAS CHANGED 경고
서버를 재설치했거나, 같은 IP에 다른 VM이 할당됐거나, 클라우드 인스턴스를 새로 만들어 탄력적 IP를 옮겨 붙인 뒤 접속하면 아래 경고와 함께 접속이 거부됩니다.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:...
Please contact your system administrator.
Add correct host key in /home/me/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /home/me/.ssh/known_hosts:3
Host key verification failed.
이 경고는 네트워크 문제가 아니라 보안 장치입니다. SSH 클라이언트는 처음 접속한 서버의 호스트 키를 ~/.ssh/known_hosts에 저장해 두고, 다음 접속부터 같은 키인지 비교합니다. 키가 다르면 중간자 공격일 가능성을 배제할 수 없으므로 접속을 막습니다. 서버를 재설치하면 호스트 키가 새로 생성되므로 이 경고는 예상된 결과입니다.
재설치나 IP 재할당처럼 키가 바뀐 이유를 확실히 알 때만 기존 항목을 지웁니다. 이유를 모르는데 경고가 떴다면, 특히 공용 네트워크에서라면, 먼저 다른 경로로 서버의 실제 키 지문을 확인하는 것이 맞습니다.
# 서버 콘솔에서 현재 호스트 키 지문 확인
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# 클라이언트에서 해당 호스트의 옛 키 삭제
ssh-keygen -R 203.0.113.10
# 22번이 아닌 포트로 접속하던 서버는 [주소]:포트 형식으로 저장되어 있음
ssh-keygen -R "[203.0.113.10]:2222"
윈도우에서도 같은 명령이 동작하며, 파일 위치는 C:\Users\<사용자>\.ssh\known_hosts입니다. 경고 마지막 줄의 known_hosts:3은 3번째 줄이 문제라는 뜻이므로 편집기로 그 줄만 지워도 됩니다. known_hosts 파일을 통째로 지우는 것은 다른 서버들의 검증 기록까지 날려 버리므로 피하는 게 좋습니다. 다시 접속하면 새 키의 지문을 보여 주며 Are you sure you want to continue connecting (yes/no/[fingerprint])?를 묻는데, 여기서 앞서 서버 콘솔에서 확인한 지문과 같은지 비교하고 yes를 입력합니다.
접속 문제를 줄이려면: 설정을 되돌리는 법과 다음 단계
SSH 설정을 바꿀 때 가장 큰 위험은 원격 서버에서 스스로를 잠그는 것입니다. 다음 습관 몇 가지가 이를 막아 줍니다.
- 설정 파일을 고치기 전에 백업합니다. 우분투 24.04는
/etc/ssh/sshd_config.d/아래 파일을 읽으므로, 원본sshd_config를 건드리지 않고/etc/ssh/sshd_config.d/10-custom.conf같은 파일을 새로 만들어 바꾸면 그 파일만 지워서 원상 복구할 수 있습니다. 단, 같은 항목이 여러 곳에 있으면 먼저 읽힌 값이 적용되는 sshd의 규칙 때문에 의도와 다르게 동작할 수 있으니sudo sshd -T | grep -i port로 최종 적용 값을 확인합니다. - 변경 후에는
sudo sshd -t로 문법을 검사하고, 기존 세션을 유지한 채 새 창에서 접속을 확인합니다. - 클라우드라면 웹 콘솔(시리얼 콘솔) 접근 방법을 미리 확인해 둡니다. 방화벽이나 sshd 설정 실수로 잠겼을 때 유일한 복구 경로가 됩니다.
접속이 다시 되기 시작했다면, 이번에 문제의 원인이 된 지점을 정리하는 것이 다음 단계입니다. 비밀번호 로그인을 끄고 키 인증으로 바꾸기, 접속 IP 제한, ~/.ssh/config로 서버별 사용자·포트·키를 고정해 ssh myserver 한 단어로 접속하기 같은 설정은 SSH 원격 접속 명령어와 실무 팁 글에서 이어서 다룹니다. 특히 ~/.ssh/config에 포트를 적어 두면 “포트를 바꿔 놓고 -p를 빼먹어서 refused”라는, 이 글 전체에서 가장 흔한 실수 하나가 사라집니다.