[Linux] Ubuntu 24.04에서 sshd 설정이 안 먹는 세 가지 이유
서버 여러 대를 Ubuntu 24.04로 재설치하면서 SSH 포트를 기본 22가 아닌 다른 포트로 옮기는 작업을 반복했다. /etc/ssh/sshd_config에 Port를 적고 서비스를 재시작하면 끝나야 할 일인데, 노드마다 "설정은 분명 맞는데 22번이 계속 열려 있는" 상황이 재현됐다. 파고들어 보니 원인이 하나가 아니라 셋이고, 각각 서로 다른 층(systemd 소켓, sshd 설정 파서, 서비스 종료 정책)에 있었다. 22.04까지의 감각으로는 전부 헛다리를 짚게 되는 지점들이라 정리해 둔다.
증상
sshd_config에Port 2222를 넣고systemctl restart ssh를 했는데 여전히 22번에서 듣는다- drop-in에
PasswordAuthentication no를 넣었는데sshd -T는yes를 답한다 systemctl disable --now ssh.socket을 했는데도 22번이 안 닫힌다- 재시작 후 새 포트와 옛 포트가 동시에 열려 있다
원인 ① — ssh.socket이 포트를 가져간다
24.04의 openssh-server는 systemd 소켓 활성화가 기본이다. 포트를 sshd가 아니라 systemd가 열고, 접속이 오면 sshd에 넘겨준다. 이 구조에서는 sshd_config의 Port 지시가 그냥 무시된다 — 포트의 주인이 sshd가 아니기 때문이다.
재미있는 판별법이 있다. ss -tln으로 리스닝 소켓의 백로그(Send-Q)를 보면 주인이 갈린다:
State Recv-Q Send-Q Local Address:Port
LISTEN 0 4096 0.0.0.0:22 ← systemd(ssh.socket)의 백로그
LISTEN 0 128 0.0.0.0:2222 ← sshd 자신이 연 소켓
systemd 소켓은 백로그 4096, sshd 자신의 리스너는 128이다. 22번의 Send-Q가 4096이면 그 포트는 sshd 설정으로는 못 닫는다.
해결은 소켓 활성화를 끄고 전통적인 서비스 방식으로 돌아가는 것:
sudo systemctl disable --now ssh.socket
sudo systemctl mask ssh.socket # 패키지 업데이트가 되살리는 것까지 차단
sudo systemctl enable --now ssh.service
mask까지 해두는 이유: openssh 패키지가 업데이트되면서 socket 유닛을 다시 활성화하는 경우가 있다.
원인 ② — drop-in은 번호가 낮을수록 이긴다
sshd 설정은 먼저 읽힌 값이 이긴다(first match wins). 그리고 sshd_config 맨 위의 Include /etc/ssh/sshd_config.d/*.conf가 파일을 사전순으로 읽는다. 조합하면: 50-cloud-init.conf가 99-custom.conf를 무력화한다.
sysctl이나 systemd drop-in은 "나중에 읽힌(번호 큰) 쪽이 이기는" 관례라, 습관적으로 99-를 붙이면 정확히 반대로 동작한다. 실제로 99-custom.conf에 PasswordAuthentication no를 넣었는데 sshd -T가 yes를 답했다 — 설치 관리자에서 "비밀번호 인증 허용"을 선택하면 cloud-init이 50-cloud-init.conf에 PasswordAuthentication yes를 써두고, 그게 먼저 읽히기 때문이다.
해결은 내 설정 파일이 항상 먼저 읽히게 하는 것:
sudo mv /etc/ssh/sshd_config.d/99-custom.conf /etc/ssh/sshd_config.d/01-custom.conf
sudo sshd -T | grep -E "^port|^passwordauthentication" # 유효값 재확인
원인 ③ — KillMode=process, 재시작해도 옛 리스너가 산다
Ubuntu의 ssh.service는 KillMode=process다. 서비스 재시작 때 메인 프로세스만 죽이고 자식(기존 SSH 세션)은 살려두려는 의도인데, 부작용이 있다: 부팅 때부터 22번을 듣던 sshd가 재시작 후에도 남을 수 있다. 새 sshd는 2222에서 뜨는데 옛 sshd가 22에서 계속 듣는 이중 상태가 된다.
남은 리스너는 직접 정리한다:
for p in $(sudo ss -tlnp | grep ":22 " | grep -oP "pid=\K[0-9]+" | sort -u); do
sudo kill "$p"
done
주의: 이 시점에 필요한 sshd가 22에서 "정상적으로" 듣고 있는 경우(원인 ①·②가 안 풀린 상태)에 이걸 돌리면 SSH가 통째로 내려간다. 콘솔 접근 수단을 확보하고 하거나, 새 포트 리스너가 뜬 것을 확인한 뒤에 하라.
덤 — sudo 없는 ss는 거짓말을 한다
ss -tlnp | grep sshd를 일반 유저로 돌리면 프로세스명 컬럼이 통째로 비어서 결과가 없는 것처럼 보인다. 포트는 멀쩡히 열려 있는데 "sshd가 안 떴다"고 오판하기 딱 좋다. sudo ss -tlnp로 보거나, 프로세스명 말고 포트로 걸러라(ss -tln | grep 2222).
검증은 반드시 두 방향에서
# 서버 안에서: sshd가 실제로 적용한 유효값
sudo sshd -T | grep -E "^port|^passwordauthentication"
# 서버 밖에서: 실제로 열린 포트
nc -z -w2 <서버> 22 # 닫혀 있어야 정상
nc -z -w2 <서버> 2222 # 열려 있어야 정상
안에서 본 유효값과 밖에서 본 개방 상태가 일치해야 끝난 것이다. 하나만 보고 판단하면 위의 세 함정 중 하나에 걸린 상태를 "완료"로 착각하게 된다.
교훈
- 24.04에서 sshd의 포트 설정이 안 먹으면 설정 파일보다 소켓 유닛을 먼저 의심하라.
ss -tln의 백로그 숫자가 가장 빠른 판별법이다. - sshd drop-in의 우선순위는 다른 시스템들과 정반대다. 접두 번호는 낮게.
- "재시작했으니 반영됐겠지"는 KillMode 때문에 성립하지 않는다. 밖에서 포트를 직접 찔러 확인하라.
댓글
아직 댓글이 없습니다. 첫 댓글을 남겨보세요.