Permission denied (publickey)는 가장 많이 마주치는 SSH 오류이고, 그 메시지는 전혀 도움을 주지 않습니다. 이건 “네 키가 틀렸다”는 뜻이 아닙니다. 이것은 서버가 내가 제시한 모든 인증 방법을 거부했고, 공개 키가 서버가 논의할 의향이 있던 유일한 방법이었다는 뜻입니다. 괄호 안은 아직 열려 있는 방법의 목록입니다 — (publickey)는 비밀번호 인증이 꺼져 있어 키가 통해야만 하는데, 내 키 중 어느 것도 통하지 않았다는 뜻이죠.
목록은 더 길 수 있고, 읽어 볼 가치가 있습니다. **Permission denied (publickey,password)**는 서버가 비밀번호도 받겠다는 뜻입니다 — 그러니 비밀번호를 입력하려 했는데 프롬프트가 뜨지 않았다면, 클라이언트가 키에서 포기하고 비밀번호로 넘어갔어야 했던 겁니다. -o PubkeyAuthentication=no로 프롬프트를 강제해 테스트하세요. **Permission denied (publickey,keyboard-interactive)**는 같은 발상이되 대화형 방법(흔히 PAM 프롬프트나 2FA)이 아직 열려 있는 경우입니다. 괄호 안에 있는 것은 서버가 남겨 둔 문의 전체 집합입니다. 기대한 문이 목록에 없다면, 서버는 애초에 그걸 받아 줄 생각이 없었던 것입니다.
그물이 넓습니다. 틀린 사용자명이 이 오류를 냅니다. 클라이언트가 아예 제시하지 않은 키, 서버가 받지 못한 키, sshd가 조용히 눈감아 주지 않는 권한 문제, 그리고 들어 본 적도 없는 SELinux 라벨도 마찬가지입니다. 해결은 추측이 아니라 체계적입니다 — 여기 그 루프가 있고, 이어서 실제로 답일 확률이 높은 순서대로 용의자가 나옵니다. (GitHub나 GitLab로 푸시하는 중인가요? 그건 다른 체크리스트입니다 — GitHub/GitLab SSH 키가 안 될 때.)
진단 루프: 클라이언트가 무엇을 시도했는지 읽기
실패하는 연결을 최대 상세 모드로 실행하세요(그리고 쏟아지는 출력이 잡음처럼 보인다면, ssh -vvv 읽는 법(영어)이 중요한 줄들을 해독해 줍니다):
ssh -vvv user@host
출력에서 세 가지를 찾으세요:
Authentications that can continue: publickey— 서버의 방법 목록입니다.password가 없으면 비밀번호는 결코 묻지 않으니, 키가 성공해야 합니다.Offering public key: /home/you/.ssh/id_ed25519— 클라이언트가 시도한 모든 키입니다. 내가 의도한 키가 이 목록에 없으면 문제는 클라이언트 쪽(범인 2)입니다. 있다면 —- 무엇이 되돌아왔는지.
Server accepts key다음에 서명 교환이 이어지면 키는 맞았고 이후 무언가가 실패한 것입니다(드묾). 보통은 제시 직후 바로 다음 키나Permission denied가 이어집니다 — 서버가 키를 보고 어깨를 으쓱한 것이고, 서버 쪽(범인 3–8)을 가리킵니다.
상자로 들어가는 다른 길이 있다면(사업자 웹 콘솔, 다른 사용자, 다른 관리자), 서버 로그가 진짜 이유를 대놓고 짚어 줍니다:
sudo journalctl -u sshd -f # systemd 배포판
sudo tail -f /var/log/auth.log # Debian/Ubuntu
sudo tail -f /var/log/secure # RHEL/Alma/Rocky
Authentication refused: bad ownership or modes for directory /home/deploy(디렉터리의 소유권이나 권한이 잘못됨) 같은 줄은 조사를 즉석에서 끝냅니다.
범인 1: 틀린 사용자
단연 가장 흔한 원인이고, 특히 클라우드 이미지에서 그렇습니다(첫 EC2나 VPS 로그인(영어)의 첫 벽입니다). 로그인 사용자가 짐작과 다르기 때문입니다: Ubuntu 이미지는 ubuntu, Amazon Linux는 ec2-user, Debian AMI는 admin, 대부분의 맨 VPS는 root, Azure 기본값은 azureuser. 맞는 키에 틀린 사용자명은 정확히 이 오류를 냅니다 — 서버가 ~wronguser/.ssh/authorized_keys를 보고, 아무것도 찾지 못해 거부합니다.
다른 것을 건드리기 전에, 이미지 문서가 명시한 사용자를 확인하고, ~/.ssh/config에 박아 두어 다시 입력하지 않게 하세요(ssh_config 가이드(영어)가 패턴을 다룹니다):
Host web1
HostName 203.0.113.10
User ubuntu
범인 2: 키가 아예 제시되지 않음
ssh -vvv가 Offering public key 줄에 내 키를 보여 주지 않으면, 클라이언트가 그 키를 모르는 것입니다. 명시적으로 가리키세요:
ssh -i ~/.ssh/id_ed25519 user@host
그걸로 되면, 위 config 블록의 IdentityFile로 영구화하세요. 관련된 함정 둘: 키가 많이 쑤셔 넣어진 에이전트는 맞는 키에 닿기 전에 서버의 시도 한도에 걸릴 수 있고(Too many authentication failures — IdentitiesOnly yes로 고칩니다), 암호구 입력을 취소한 키는 조용히 건너뜁니다. 에이전트가 실제로 뭘 쥐고 있는지 확인하세요:
ssh-add -l
Windows에서는 방금 키를 올렸는데도 이 목록이 비어 보일 수 있습니다. Git Bash, OpenSSH 서비스, WSL이 저마다 별개의 에이전트를 돌리고, ssh-add -l은 지금 실제로 쓰는 ssh에 대해서만 답하기 때문입니다. Windows의 ssh-agent가 이 셋을 풀어 줍니다.
범인 3: 공개 키가 서버에 없음
공개 쪽 절반이 그 사용자의, 그 사용자 홈의 ~user/.ssh/authorized_keys에 한 줄로 있어야 합니다. 거기에 넣는 믿을 만한 방법(복사를 위해 비밀번호 인증이나 기존 키를 씁니다):
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
손으로 — 가령 사업자 콘솔을 통해 — 할 때는, 그 한 줄을 추가하되 파일을 절대 덮어쓰지 마세요:
mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys
# id_ed25519.pub의 한 줄을 붙여 넣고, Enter, Ctrl-D
고전적인 실수: 키가 root의 파일에 들어갔는데 로그인은 deploy로 하고 있다, 편집기가 줄을 접어서 이제 두 줄이 됐다, 개인 키를 붙여 넣었다(파일이 ssh-ed25519 AAAA…로 시작하면 맞고 — -----BEGIN이 보이면 잘못된 절반입니다).
범인 4: 권한과 소유권
sshd의 StrictModes(기본 켜짐)는 authorized_keys로 가는 경로가 소유자 외의 누군가에게 쓰기 가능하면 그 파일을 신뢰하지 않습니다. 이게 바로 그 고전적인 “키를 복사했는데도 여전히 안 돼”입니다. 전체 해법은 대상 사용자로 실행하세요:
chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R $USER:$USER ~/.ssh
홈 디렉터리 줄이 중요한데도 잊히곤 합니다. 그룹 쓰기 가능한 /home/deploy는, 전체 읽기 가능한 키 파일만큼이나 똑같이 검사에 걸립니다. 서버 로그의 bad ownership or modes 줄이 어느 디렉터리가 문제인지 정확히 알려 줍니다.
범인 5: 틀린 키 형식 또는 암호구
OpenSSH는 PuTTY의 .ppk 파일을 읽지 못합니다 — -i로 그걸 가리키면 상세 출력에서 invalid format으로 실패합니다. PuTTYgen에서 OpenSSH 형식 키를 내보내거나(Conversions → Export OpenSSH key), 새 현대 키를 생성해 등록하세요(거의 모든 경우 Ed25519(영어)). Windows를 쓰면서 아직 PuTTYgen에서 벗어나지 못했다면, PuTTY 세션을 가져오고 OpenSSH 키를 바로 쓰는 Windows용 SSH 클라이언트가 이 변환 단계를 아예 없애 줍니다. 개인 키 파일이 읽히는지, 암호구가 생각한 그것인지 확인하려면, 공개 쪽 절반을 출력하게 시켜 보세요:
ssh-keygen -y -f ~/.ssh/id_ed25519
그게 키를 출력하면 파일과 암호구는 멀쩡합니다 — 그리고 그 출력을 authorized_keys의 줄과 대조해 실제로 같은 키인지 확인할 수 있습니다.
범인 6: 서버 설정이 막음
덜 흔하지만, 서버 접근이 있을 때 확인은 간단합니다. sshd가 실제로 무슨 설정으로 돌고 있는지 물으세요:
sudo sshd -T | grep -Ei 'pubkeyauthentication|authorizedkeysfile'
PubkeyAuthentication은 yes여야 하고(기본값이지만 하드닝 스크립트가 가끔 뒤집습니다), AuthorizedKeysFile은 sshd가 어디를 보는지 알려 줍니다 — 누군가 그걸 /etc/ssh/authorized_keys/%u로 가리켜 놨다면, 정성껏 놓아 둔 ~/.ssh/authorized_keys가 무시되고 있는 겁니다. /etc/ssh/sshd_config를 바꾼 뒤에는:
sudo systemctl reload sshd
범인 7: SELinux 컨텍스트 (RHEL 계열)
RHEL, Alma, Rocky, Fedora 등에서는 흔치 않은 방식으로 만든 ~/.ssh — 백업에서 복원, root로 복사, 마운트된 볼륨에서 생성 — 가 잘못된 SELinux 라벨을 지닐 수 있고, 그러면 sshd가 권한이 완벽한 파일에 대한 읽기 접근을 거부당합니다. 위의 모든 게 통과되고, 오류는 계속되며, ls -Z ~/.ssh가 ssh_home_t가 아닌 무언가를 보여 줍니다. 명령 하나가 라벨을 복구합니다:
restorecon -R -v ~/.ssh
RHEL 계열 상자에서 아이디어가 바닥났다면 그냥 실행해 보세요 — 라벨이 이미 맞았다면 무해합니다.
범인 8: root 로그인이 비활성화됨
현대 기본값은 PermitRootLogin prohibit-password(키 전용)나 no(절대 안 됨)로 설정합니다. root@host를 시도 중이고 키가 정말로 /root/.ssh/authorized_keys에 있다면, 확인하세요:
sudo sshd -T | grep -i permitrootlogin
no이면 어떤 자격 증명도 root에 통하지 않습니다 — 비특권 사용자로 로그인하고 sudo를 쓰세요. 어차피 기본값이 밀어붙이는 방식이 그것입니다.
빠른 답변
Permission denied (publickey)는 내 키가 손상됐다는 뜻인가요?
거의 아닙니다. 서버가 내가 제시한 방법을 하나도 받아들이지 않았다는 뜻입니다 — 보통 깨진 키가 아니라 틀린 사용자나 틀린 키입니다. 키가 읽히는지, 암호구가 맞는지 ssh-keygen -y -f ~/.ssh/id_ed25519로 확인하세요.
(publickey)와 (publickey,password)의 차이는 뭔가요?
괄호는 서버가 아직 허용하는 방법을 나열합니다. (publickey)는 키 전용이고, (publickey,password)는 비밀번호도 통한다는 뜻이라 프롬프트가 떴어야 합니다 — 안 떴다면 클라이언트가 키를 다 소진한 뒤 포기한 것입니다.
어제는 됐는데 지금은 안 됩니다 — 뭐가 바뀐 건가요?
다시 빌드된 서버, 교체된 키, 또는 타임아웃 후 키를 떨군 에이전트. 먼저 ssh-add -l로 뭐가 로드됐는지 보고, 상자가 재이미징됐는지 확인하세요(host key verification failed(영어)도 함께 던지는 증상입니다).
다시는 겪지 않기
위 범인 거의 전부는 다시 유도할 필요 없는 호스트별 사실입니다: 어느 사용자, 어느 키, 어느 포트인지. ~/.ssh/config에 박아 두면 이 오류 부류는 대체로 사라집니다 — 그리고 남는 오류들은 해독기가 마주칠 나머지 아홉 가지를 다룹니다.
같은 사실들이 닷파일 대신 클라이언트에 살 수도 있습니다. Termalin은 사용자·포트·키를 저장된 호스트와 함께 보관하고, 내장 에이전트로 키를 한 번 잠금 해제하며(암호구 취소가 키를 조용히 건너뛰는 일 없음), 첫 연결 때 서버 신원을 검증하고, 호스트별 실시간 상태를 보여 줍니다 — 그래서 “애초에 떠 있나?”와 “맞는 키를 쓰고 있나?”가 더 이상 진단 단계가 아니게 됩니다. PuTTY 세션도(영어) 바로 가져오므로 범인 5를 영영 은퇴시킵니다.
Termalin은 호스트별 사용자·포트·키를 호스트와 함께 보관하고 첫 연결 때 서버를 검증하는 무료 크로스 플랫폼 SSH 클라이언트입니다 — 다운로드하거나, 키를 안전하게 다루는 방식을 읽어 보세요.