Devin.KR
로그인

리눅스 nc 명령어 사용법 - 포트 열림 확인과 임시 리스너 만들기

개발자 조회 1

이 명령어를 언제 쓰는가

"방화벽 열어달라고 했는데 열린 건가?" 이 질문에 답하는 도구다. ping은 ICMP만 확인할 뿐 TCP 포트와는 무관하고, telnet은 종료가 번거롭다. nc지정한 포트로 TCP 연결이 실제로 맺어지는지를 한 줄로 확인하고 종료 코드까지 정직하게 돌려준다.

또 하나의 핵심 용도는 임시 리스너다. 애플리케이션을 배포하기 전에 "이 포트로 트래픽이 도달하긴 하나"를 미리 검증할 수 있다. 방화벽 담당자와 핑퐁하는 시간을 크게 줄여준다.

서버끼리 파일을 급히 옮기거나, HTTP·SMTP 같은 텍스트 프로토콜에 직접 말을 걸어보는 용도로도 쓴다. 여기서는 진단 용도만 다룬다.

기본 형식

nc [옵션] 호스트 포트          # 접속 모드
nc -l [옵션] 포트              # 리스닝 모드
  • 접속 모드 — 지정한 호스트·포트로 TCP 연결을 시도하고, 표준 입력을 그대로 보낸다.
  • 리스닝 모드 — 그 포트로 들어오는 연결을 받는다. 실제 서비스를 대신 세워보는 셈이다.
  • 포트 인자는 하나뿐이다. nc -zv host 20-25 처럼 범위는 줄 수 있지만, nc -zv host 80 443처럼 떨어진 포트를 나열하면 netcat-openbsd는 두 번째 이후 인자를 조용히 무시한다. 여러 포트는 반복문으로 돌린다.

구현이 여러 개다

이름이 같아도 속은 다르다. 옵션이 안 먹으면 대부분 이 이유다.

구현주로 쓰이는 곳특징
netcat-openbsdDebian/Ubuntu 기본, macOS-l 포트 형태. -z, -k, -N 지원
nmap-ncatRHEL/Rocky (nc가 이것)ncat과 동일. SSL·프록시 기능이 있다
netcat-traditional구형 Debian, 일부 임베디드리스닝에 -l -p 포트가 필요. -e가 있어 보안상 기피된다
busybox ncAlpine 컨테이너옵션이 매우 제한적. -z가 없을 수 있다

어느 것인지 모르겠으면 nc -h를 먼저 친다. 사용법 첫 줄만 봐도 구분된다.

자주 쓰는 옵션

옵션의미예시
-z데이터를 주고받지 않고 연결만 시도(스캔 모드)nc -z devin.kr 443
-v결과를 사람이 읽게 출력. -z와 항상 같이 쓴다nc -zv devin.kr 443
-w타임아웃(초). 안 붙이면 막힌 포트에서 오래 매달린다nc -zv -w 3 devin.kr 443
-l리스닝 모드nc -l 9000
-k연결이 끊겨도 리스너를 계속 유지nc -lk 9000
-uTCP 대신 UDPnc -zvu -w 2 10.0.0.5 53
-nDNS 조회 생략nc -zvn 10.0.0.5 22
-4 / -6IPv4 / IPv6 강제nc -4zv devin.kr 443
-N입력이 끝나면 소켓을 닫는다(파일 전송 시 필요)nc -N host 9000 < file

실전 예제

1. 포트가 열려 있는지 확인한다. 방화벽 신청 후 검증에 그대로 쓰는 형태다.

nc -zv -w 3 devin.kr 443
Connection to devin.kr port 443 [tcp/https] succeeded!

닫혀 있거나 필터링되면 이렇게 나온다.

nc: connectx to devin.kr port 4567 (tcp) failed: Operation timed out

실패 메시지를 구분해서 읽는 것이 중요하다. Connection refused는 패킷이 도달했고 그 포트에 아무도 없다는 뜻이므로 경로는 정상이다. Operation timed out(리눅스에서는 보통 Connection timed out)은 응답 자체가 없다는 뜻으로 중간 방화벽이 조용히 버렸을 가능성이 크다. 문구는 구현마다 조금씩 다르지만 이 두 갈래의 의미는 같다.

2. 여러 포트를 한 번에 확인한다. 신규 서버 개통 점검에 쓴다.

for p in 22 80 443 3306; do
    nc -zv -w 2 10.0.0.20 "$p"
done 2>&1 | grep -E 'succeeded|failed'

연속된 범위라면 반복문 없이 한 줄로 된다.

nc -zv -w 2 10.0.0.20 8000-8010

3. 스크립트에서 서비스 기동을 기다린다. 종료 코드가 정확해서 배포 스크립트에 그대로 넣을 수 있다.

for i in $(seq 1 30); do
    if nc -z -w 1 127.0.0.1 8080; then
        echo "app is up"
        exit 0
    fi
    sleep 2
done
echo "timeout waiting for 8080" >&2
exit 1

4. 애플리케이션 없이 포트 도달 여부를 검증한다. 이것이 nc의 진짜 강점이다. 서버 A에서 리스너를 띄우고, 서버 B에서 접속해본다.

# 서버 A (수신 측)
nc -lk 9000
# 서버 B (송신 측)
echo "hello from B" | nc -w 3 서버A주소 9000

서버 A 화면에 hello from B가 찍히면 그 포트로의 경로와 방화벽이 모두 정상이다. 애플리케이션이 안 뜨는 것은 별개 문제로 분리된다. -k를 빼면 리스너가 첫 연결 후 종료되므로, 반복 시험에는 -k를 붙인다.

1024 미만 포트로 리스닝하려면 root 권한이 필요하다.

5. HTTP 응답을 직접 받아본다. 로드밸런서가 어느 백엔드로 보내는지, 리다이렉트가 어디로 걸리는지 볼 때.

printf 'GET / HTTP/1.1\r\nHost: devin.kr\r\nConnection: close\r\n\r\n' | nc -w 5 devin.kr 80
HTTP/1.1 301 Moved Permanently
content-length: 0
location: https://devin.kr/
connection: close

줄 끝이 \r\n이어야 하고 헤더 뒤에 빈 줄이 하나 더 있어야 한다. echo로는 이게 안 되므로 printf를 쓴다.

6. tcpdump와 짝지어 원인을 좁힌다. 서버 쪽에서 캡처를 띄워두고 클라이언트에서 nc로 두드린다.

# 서버 쪽
sudo tcpdump -i any -nn 'port 8080'
# 클라이언트 쪽
nc -zv -w 3 서버주소 8080

서버 캡처에 SYN이 아예 안 보이면 중간 구간에서 막힌 것이고, SYN은 보이는데 응답이 없으면 서버의 로컬 방화벽이 범인이다.

함정과 주의점

UDP 확인은 신뢰할 수 없다. nc -zvu는 UDP 패킷을 하나 보내고 ICMP Port Unreachable이 안 오면 "성공"이라고 판정한다. 그런데 방화벽이 그 ICMP를 막으면 닫힌 포트도 열렸다고 나온다. UDP는 실제 프로토콜 요청을 보내 응답을 받아봐야 확실하다. DNS라면 dig @대상 +time=2, NTP라면 ntpdate -q 같은 방식이다.

-w 없이 쓰면 스크립트가 멈춘다. 필터링된 포트는 OS 기본 TCP 재시도가 끝날 때까지, 리눅스에서 2분 이상 매달린다. cron이나 헬스체크에서는 반드시 -w를 붙인다.

리스너를 띄운 채 잊지 않는다. 검증용으로 nc -lk를 띄워두고 그대로 두면 그 포트를 계속 점유한다. 나중에 실제 애플리케이션이 뜨려다 Address already in use로 실패한다. 테스트가 끝나면 Ctrl+C로 확실히 내리고, 백그라운드로 돌렸다면 ss -tlnp | grep 포트로 확인한다.

구현에 따라 옵션이 다르다. netcat-traditional에서는 리스닝에 nc -l -p 9000처럼 -p가 필요하고, busybox nc에는 -z가 없을 수 있다. Alpine 컨테이너에서 -z가 안 먹는다면 이 경우다. RHEL의 nc는 nmap-ncat이라 성공 메시지 문구가 다르다.

-e 옵션은 쓰지 않는다. netcat-traditional의 -e는 접속 시 임의 명령을 실행하는 기능으로, 사실상 원격 셸을 여는 것과 같다. 많은 배포판이 이 이유로 해당 빌드를 기본 제외했다. 진단 목적에는 필요 없는 기능이며, 서버에 그런 것을 남겨서는 안 된다.

함께 보면 좋은 명령어

  • ss — 서버 쪽에서 그 포트가 정말 LISTEN 중인지, 어느 주소에 묶였는지 확인한다.
  • telnet — nc가 없는 서버에서 같은 포트 확인을 대신한다.
  • tcpdump — nc로 두드린 패킷이 실제로 도달하는지 반대편에서 본다.
  • curl — HTTP라면 nc보다 curl이 훨씬 정확하고 편하다.