Linux VPS를 막 띄웠거나, 한밤중 모니터링 알림으로 SSH 접속이 끊겼다는 소식을 들은 적이 있을 겁니다. 터미널에 ssh: connect to host … port 22: Connection refused가 뜨는 순간 심박이 빨라지는 건 누구나 비슷합니다. VNC도 클라우드 콘솔도 없으면, 검은 화면만 바라보게 됩니다.
현장에서는 한 달에 몇 번씩 이런 문의가 옵니다. sshd_config 수정 후 reload를 잊었거나, 보안 그룹에 80/443만 열고 22를 빠뜨렸거나, fail2ban이 집 IP를 조용히 차단한 경우——원인은 제각각이지만 Connection refused는 대개 패턴이 있습니다. 이 글은 실전에서 통하는 다섯 가지 절차를 에러를 읽고 층별로 내려가는 순서로 정리했습니다. 대부분 이십 분 안에 원인이 드러납니다.
전제로, 서버에 닿을 다른 통로(클라우드 VNC, 시리얼 콘솔, 같은 VPC 안의 다른 머신)가 있다고 가정합니다. 완전히 고립됐다면 말미의 「완전 차단됐을 때」로 건너뛰세요.
들어가기 전에: 「안 붙는다」도 셋은 다르다
Connection refused, Connection timed out, Permission denied를 한 문제로 묶으면 한 시간 동안 키 파일만 의심하게 됩니다. OpenSSH 공식 문서 기준으로는 각각 다른 계층을 가리킵니다.
| 에러 키워드 | 흔한 의미 | 우선 확인 |
|---|---|---|
Connection refused |
TCP는 도착했지만 대상 포트에 대기 프로세스가 없음, 또는 본 서버 방화벽 REJECT | sshd 실행, 대기 포트, ufw/iptables |
Connection timed out |
중간에서 패킷 유실(경로, 클라우드 SG, 상류 방화벽) | 보안 그룹, 올바른 공인 IP, 포트 프로브 |
Permission denied |
SSH 핸드셰이크는 됐지만 인증 실패(키, 비밀번호, 사용자 제한) | 키 권한, AllowUsers, fail2ban IP 차단 |
-v로 멈추는 지점 보기ssh -v user@host(필요하면 -vvv)를 실행해 「Connecting」에서 멈추는지 「Authenticating」에서 멈추는지 확인하세요. 전자는 네트워크/포트, 후자는 키와 사용자 설정 문제입니다.
이 구분만 먼저 잡아도 헛수고가 크게 줄어듭니다. Connection refused는 패킷이 서버에 닿았다는 신호——문제는 서버 쪽이거나 바로 앞단입니다. timed out은 경로 어딘가에서 묵살된 것이므로, 닿지 않는 머신의 sshd_config를 만져봐야 소용없습니다. Permission denied는 TCP 세션이 이미 열렸으니 인증 정보·계정 정책·IP ban을 의심합니다.
팀에서는 인시던트 채널에 에러 문구 전체를 붙여 주세요. 「SSH 죽음」만으로는 추측이 열두 가지인데, 「사무실 IP에서 2222로 Connection refused」면 범위가 바로 좁혀집니다.
1단계: IP·DNS·포트 도달성 확인(네트워크)
sshd를 탓하기 전에 길이 뚫려 있는지 증명하세요. 신규 VPS에서 흔한 건 IP 오타, DNS 미반영, 비표준 포트로 떠 있는데 22로 접속하는 경우입니다.
내 PC에서 아래 순서로 실행합니다.
# 1. 이름 해석 IP가 맞는지 dig +short your.domain.com ping -c 3 your.server.ip # 2. SSH 포트 개방 여부(22는 실제 포트로 교체) nc -zv your.server.ip 22 # 또는 telnet your.server.ip 22 # 3. 포트를 명시해 접속(~/.ssh/config 영향 회피) ssh -p 22 -i ~/.ssh/id_ed25519 user@your.server.ip
nc가 Connection refused를 주면 패킷은 서버에 닿았습니다——원인은 본 서버 서비스나 본 서버 방화벽입니다. 2단계로. timed out이나 멈춤이면 클라우드 보안 그룹/Network ACL을 우선: 인바운드 TCP 22(또는 커스텀 포트) 허용 여부, 소스가 0.0.0.0/0인지 실수로 사설 대역만인지 확인하세요.
내 네트워크도 자주 빠뜨립니다. 회사 VPN, 캠퍼스망, 일부 ISP는 22를 필터합니다. sshd를 잠시 443이나 2222로 옮겨 비교해 보면 경로 필터인지 서버 본체인지 갈라지기 쉽습니다.
여러 대를 운영한다면 공인 IP와 SSH 포트 메모를 남기세요. 옛 티켓 IP를 복붙해 접속 안 되는 사고가 의외로 많습니다. 호스트명 접속은 TTL·캐시도 확인——레지스트라에서 고친 직후에도 내 dig +short가 옛 주소를 가리킬 수 있습니다.
2단계: sshd 서비스 실행 여부
Connection refused의 최다 원인 중 하나: sshd가 아예 안 떠 있음, 또는 OS 업그레이드 후 유닛 이름이 바뀐 경우. Ubuntu/Debian은 ssh, RHEL/CentOS/Rocky는 sshd가 일반적——추측 말고 명령으로 확인하세요.
VNC나 클라우드 콘솔로 들어간 뒤 실행합니다.
# Debian/Ubuntu sudo systemctl status ssh sudo systemctl start ssh sudo systemctl enable ssh # RHEL/CentOS/Rocky sudo systemctl status sshd sudo systemctl start sshd # 대기 중인가? 주소와 포트는? sudo ss -tlnp | grep ssh # 0.0.0.0:22 또는 [::]:22 기대 # 설정 문법 검사(편집할 때마다) sudo sshd -t sudo systemctl reload ssh # 또는 sshd
systemctl status가 failed면 즉시 sudo journalctl -u ssh -n 50 --no-pager로 로그를 봅니다. 설정 오타, HostKey 파일 누락, 잘못된 NIC에 ListenAddress 지정이 대표적입니다. 수정 후에는 반드시 sshd -t → reload 순——reload만 해서 sshd가 안 뜨고 스스로 밖으로 막는 패턴이 현장에서 정말 많습니다.
재설치 직후에는 openssh-server 설치 여부도 확인: sudo apt install openssh-server(Debian 계열), sudo dnf install openssh-server(RHEL 계열). 최소 이미지는 SSH 서버 없이 오기도 합니다.
디스크 full이면 sshd가 안 뜨거나 세션을 못 잡기도 합니다. 콘솔에서 df -h 한 번이면 충분한 경우가 많습니다. MaxStartups를 공격 대응으로 너무 조이면 부하 때 정상 연결까지 refused가 될 수 있으니 journalctl의 drop 메시지를 보세요.
3단계: 본 서버 방화벽과 클라우드 보안 그룹
sshd는 돌고 ss에도 LISTEN이 보이는데 밖에서는 refused——다음 용의자는 패킷을 버리거나 거절하는 규칙입니다. Linux 서버는 클라우드 SG(NIC 바깥)와 ufw/iptables/nftables(OS 안쪽) 이중 구조가 흔하고, 둘 다 SSH 포트를 열어야 합니다.
OS 안에서의 대표 점검:
sudo ufw status verbose
sudo ufw allow 22/tcp
sudo ufw allow 2222/tcp # 포트 변경 시
sudo ufw reload
# firewalld(CentOS 등)
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
# nftables/iptables 직접 확인
sudo iptables -L INPUT -n -v
클라우드 SG는 SSH가 죽으면 프로바이더 콘솔에서만 고칠 수 있습니다. TCP인지, 포트 범위에 SSH 포트가 포함되는지, 소스 CIDR이 한 대의 내부 호스트만이 아닌지 확인하세요. 검증 중에는 잠시 0.0.0.0/0으로 열고, 연결 확인 후 사무실 egress IP로 조이는 게 안전합니다.
Docker나 Kubernetes를 올리면 iptables가 자동으로 바뀝니다. sudo iptables-save | grep 22로 ACCEPT 앞에 DROP/REJECT가 끼었는지 보세요. 최소 노출과 SSH/HTTPS 포트 설계는 Linux 최소 노출 방화벽·SSH 대 HTTPS 의사결정 매트릭스 FAQ와 함께 보면 판단이 빨라집니다.
IPv6 놓치기도 흔합니다. IPv4 SG만 고치고 클라이언트가 AAAA로 가다 v6가 막힌 경우——ssh -4와 ssh -6으로 행동이 달라지는지 시험해 볼 가치가 있습니다.
어느 층에서 막혔는지 기록해 두면, 다음에 누가 「보안 강화」할 때 같은 장애를 덜 반복합니다. ufw만 고치고 SG를 잊는 팀은 반년 뒤 또 같은 이야기를 합니다.
4단계: 포트와 sshd_config 대조
보안상 22가 아닌 포트로 옮겼거나 ListenAddress를 내부망만으로 제한했는데 클라이언트는 22——refused의 단골입니다. 설정은 /etc/ssh/sshd_config. 핵심 항목(자세한 내용은 sshd_config 매뉴얼):
Port 2222
# ListenAddress 0.0.0.0 # 기본은 전 NIC; 127.0.0.1이면 외부 불가
PermitRootLogin prohibit-password
PasswordAuthentication no
AllowUsers deploy admin
안전한 포트 변경 순서: 새 포트 LISTEN 확인 → 방화벽 갱신 → 옛 포트 닫기. 한 번에 「22를 2222로 바꾸고 SG의 22도 닫기」하면 새 포트 검증 전에 밖으로 막힙니다.
RHEL 계열에서 SELinux가 켜져 있으면 포트 변경 후 sudo semanage port -a -t ssh_port_t -p tcp 2222가 필요할 수 있습니다. Ubuntu AppArmor도 경로 제한을 로그에 분명히 남깁니다.
클라이언트 ~/.ssh/config의 Port, HostName 오류도 확인하세요. Host prod 별칭 쓰다 -p 빠뜨리는 건 팀 공통 실수입니다.
AllowUsers/DenyUsers를 막 조였다면 TCP는 되는데 인증에서 떨어지거나 일찍 끊기는 것처럼 보일 수 있습니다. 로컬 사용자명과 서버 허용 목록을 맞춰 보세요. 배스천·ProxyJump 구성에서는 마지막 홉만 refused처럼 보이기도 합니다. 각 구간을 nc와 ssh -J로 따로 시험하면 빠릅니다.
5단계: IP 차단 확인(fail2ban / hosts.deny)
refused가 아니라 Permission denied인데 키는 맞다고 확신한다면 IP ban을 의심하세요. fail2ban은 비밀번호 실패나 이상한 핸드셰이크 뒤 iptables나 hosts.deny에 규칙을 넣습니다. fail2ban 위키에 jail 동작이 정리돼 있습니다.
서버에서 확인:
# fail2ban 상태 sudo fail2ban-client status sshd sudo fail2ban-client set sshd unbanip YOUR.CLIENT.IP # 전통적 hosts 기반 차단 grep -v '^#' /etc/hosts.deny grep -v '^#' /etc/hosts.allow # 클라우드 「운영 잠금」이나 DDoS 완화 # → 콘솔에서 보안 알림·임시 IP 차단 확인
스스로를 ban 하는 일도 흔합니다. 스크립트 오동작으로 짧은 시간에 실패 로그가 쏟아지면 사무실 egress IP가 jail에 들어갑니다. 해제 후 ignoreip에 관리망을 넣거나, 비밀번호 인증을 끄고 키만 쓰면 오탐이 줄어듭니다.
Jenkins나 GitLab Runner처럼 VPS로 SSH 백하는 Agent를 쓰면 등록 실패가 SSH 이상처럼 보이기도 합니다. 하이브리드 토폴로지에서는 Controller와 Agent 경로를 따로 그리는 게 낫습니다——Jenkins 하이브리드 토폴로지: VPS Controller와 클라우드 Mac JNLP 엔터프라이즈 풀을 참고하세요.
완전 차단됐을 때: 구조 경로를 쓰자
다섯 단계로도 안 되면 우선순위대로 시도합니다.
- 클라우드 VNC/시리얼 콘솔——SSH 없이 직접 로그인해 설정 수정
- 스냅샷 롤백——변경 전에 찍어 뒀다면 밤샘보다 싸다
- 싱글 유저 모드/구조 디스크——원 디스크 마운트 후 chroot로
sshd_config편집 - 지원 티켓——벤더가 임시로 포트를 열거나 차단을 풀어 주는 경우도 있음
교훈은 하나: 유일한 SSH 세션에서 「끊길 수 있는 변경」을 하지 말 것. 두 번째 터미널을 열거나 tmux를 쓰세요——방화벽과 sshd 편집은 특히 그렇습니다.
복구 후 세 줄 회고만 남겨도 다음 온콜이 고맙습니다. 무엇을 바꿨는지, 어떤 신호를 놓쳤는지, 어떤 백업 경로가 살렸는지——그 정도면 충분합니다.
예방 체크리스트: 다음 당황을 줄이기
인시던트 뒤 십 분만 투자하면 다음 패닉이 싸집니다.
- 키 인증+비밀번호 끄기,
~/.ssh/authorized_keys권한 600 - 비표준 포트는 OK——보안 그룹과 sshd_config를 함께 변경
- fail2ban
ignoreip에 신뢰 네트워크 등록 - reload 전
sshd -t, 위험한 변경 전 스냅샷 - 모니터링은 SSH 22 생사만 믿지 말고 Agent·내부망 헬스체크 병행
고정 egress IP 배스천 한 대를 두고 프로덕션 SG는 거기서만 허용——카페 Wi‑Fi IP를 유일한 열쇠로 두지 않는 설계가 장기적으로 편합니다.
안정적인 배스천으로, 점검 불안을 줄이기
Linux VPS를 여러 대 운영할 때 고정 egress IP 배스천으로 SSH를 중계하는 구성이 흔합니다. 프로덕션 SG는 배스천만 허용하고, 내 노트북에서는 키로 체인 접속. Mac mini는 Unix 환경이 그대로이고 터미널·OpenSSH가 기본으로 있어 잘 맞습니다. M4 칩은 대기 시 약 4W——24시간 켜 두는 중계 노드로 책상 아래 x86 소형보다 조용하고 전력도 적습니다.
같은 가격대 Windows를 상시 가동하면 전력과 팬 소음이 눈에 띕니다. macOS는 장시간 가동 안정감이 있고 FileVault·Gatekeeper로 개인키 보관 부담도 줄어듭니다. Xcode나 Docker로 릴리스도 배스천과 겸하고 싶다면 클라우드 Mac mini로 중계+빌드를 한 노드에 모아 컨텍스트 전환을 줄일 수 있습니다.
믿을 만한 원격 운영 기반을 짤 계획이라면, VPSSPark 클라우드 Mac mini M4는 저전력 배스천 겸 개발 노드로 현실적인 선택입니다—— 요금제 보기 . 한밤중 SSH 점검을 혼자 끌어안지 않도록.