DB 접속 실패 로그가 쏟아지는데 애플리케이션 설정이 틀린 건지 포트가 막힌 건지 알 수 없습니다. ping은 성공하지만 TCP 3306 연결은 별개의 문제입니다.
L4 포트 점검을 빠르게 끝내야 앱, 방화벽, 서비스 중 어디를 볼지 결정할 수 있습니다.
L4 포트 통신 점검: telnet과 nc
서비스가 갑자기 안 된다는 신고를 받았을 때, 가장 먼저 해야 할 일은 네트워크 레이어를 단계적으로 좁혀 나가는 것입니다. L3(IP)까지는 ping으로 확인했다면, 다음은 L4(TCP/UDP 포트)가 열려 있는지 확인해야 합니다.
이 챕터에서는 현장에서 가장 많이 사용하는 두 도구 — telnet과 nc(netcat) — 를 사용하여 포트 통신을 점검하는 방법을 익힙니다.
오전 9시, 개발팀에서 "새로 배포한 API 서버에 연결이 안 된다"는 티켓이 들어옵니다. 애플리케이션 로그에는 아무것도 없습니다. 이 상황에서 인프라 엔지니어가 가장 먼저 하는 것은 포트 레벨에서 통신이 되는지 확인하는 것입니다.
telnet api-server 8080 하나로 문제가 방화벽인지, 데몬인지, 아니면 네트워크 경로인지를
30초 안에 구분할 수 있습니다. 이 판단이 빠를수록 장애 복구 시간(MTTR)이 줄어듭니다.
telnet으로 포트 연결 확인
telnet은 원래 원격 터미널 접속 프로토콜이지만, 오늘날 인프라 엔지니어들은 포트 연결 테스트 도구로 주로 사용합니다.
- 1telnet을 포트 연결 테스트 도구로 활용하는 방법
- 2TCP 3-Way Handshake 성공·실패 유형별 결과 해석
- 3Connection Refused와 Connection Timeout의 근본적 차이
- 4nc(netcat)의 -z/-v/-u/-l 옵션과 포트 스캔 패턴
- 5iptables DROP vs REJECT 차이와 방화벽 동작 시뮬레이션
- 6포트 점검 표준 절차(SOP) 스크립트 작성
which telnet || apt-get install -y telnetnc -h 2>&1 | head -3ss -tlnpiptables 규칙 추가/삭제 실습에는 root(sudo) 권한이 필요
telnet의 포트 연결 테스트 원리
서비스가 올라가 있는데 외부에서 접속이 안 됩니다. curl도 타임아웃, 브라우저도 응답 없음입니다. 방화벽인지, 프로세스가 안 떴는지, 바인딩 주소가 잘못됐는지 짐작만 됩니다. telnet <host> <port> 한 줄이면 포트까지 TCP 연결이 되는지 여부를 즉시 확인할 수 있습니다.

telnet은 지정한 호스트와 포트로 TCP 3-way handshake를 시도합니다.
클라이언트 → SYN → 서버:포트
클라이언트 ← SYN-ACK ← 서버:포트 (포트가 열려있으면)
클라이언트 → ACK → 서버:포트
handshake가 성공하면 포트가 열려 있는 것입니다. 실패하는 방식에 따라 원인이 달라집니다:
- 즉시 "Connection refused" → TCP RST 패킷 수신 → 서버에 도달했으나 해당 포트에 LISTEN 프로세스 없음
- 일정 시간 후 Timeout → 패킷이 응답 없이 사라짐 → 방화벽(ACL, Security Group, iptables)이 DROP
- 연결 성공 후 빈 화면 → TCP 연결 수립됨 → 포트 정상 오픈
telnet은 TCP 전용입니다. UDP 포트 확인에는 nc를 사용해야 합니다.
기본 사용법
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part3/exam_12 && cd /tmp/networking/part3/exam_12
# 기본 형식
telnet [호스트] [포트]
# 예시: 웹 서버 80 포트 확인
telnet 192.168.1.100 80
# 예시: HTTPS 443 포트 확인
telnet google.com 443
# 예시: MySQL 3306 포트 확인
telnet db-server 3306
- 핵심 출력—명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
- 대상 식별—IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
- 다음 분기—결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다
결과 해석
Case 1 - 포트 열림 (연결 성공)
Trying 192.168.1.100...
Connected to 192.168.1.100.
Escape character is '^]'.
이 상태에서 빈 화면이 나타나면 TCP 연결이 수립된 것입니다. Ctrl+] 후 quit으로 종료합니다.
Case 2 - Connection Refused (서비스 없음)
Trying 192.168.1.100...
telnet: Unable to connect to remote host: Connection refused
호스트에는 도달했지만 해당 포트에서 수신 대기 중인 프로세스가 없습니다.
Case 3 - Connection Timeout (방화벽 차단)
Trying 192.168.1.100...
(응답 없음... 시간 경과 후)
telnet: Unable to connect to remote host: Connection timed out
패킷이 방화벽에서 DROP되고 있습니다.
실제 공개 서버로 telnet 테스트를 연습합니다.
1단계: HTTP 포트 확인
telnet google.com 80
연결되면 아래처럼 HTTP 요청을 직접 입력해볼 수 있습니다:
GET / HTTP/1.0
Host: google.com
(빈 줄 두 번 입력)
HTML 응답이 반환되면 telnet으로 HTTP 통신이 가능함을 확인한 것입니다.
2단계: 존재하지 않는 포트로 Refused 확인
# 로컬에서 열려있지 않은 포트로 테스트
telnet localhost 9999
예상 결과:
Trying ::1...
telnet: connect to address ::1: Connection refused
3단계: 방화벽 테스트용 Timeout 시뮬레이션
iptables로 임시 DROP 규칙을 추가한 후 테스트합니다 (root 필요):
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# DROP 규칙 추가
sudo iptables -I INPUT -p tcp --dport 8888 -j DROP
# 다른 터미널에서 nc로 8888 포트 열기
nc -l 8888 &
# telnet으로 접속 시도 (Timeout 발생)
timeout 10 telnet localhost 8888
# 규칙 제거
sudo iptables -D INPUT -p tcp --dport 8888 -j DROP
nc(netcat)로 포트 스캔
nc(netcat)는 "네트워크의 스위스 아미 나이프"라 불리는 도구입니다. TCP/UDP 포트 스캔, 간이 서버, 파일 전송 등 다양한 용도로 활용됩니다.
nc -zv 옵션 이해
nc의 포트 스캔에 사용하는 핵심 옵션:

| 옵션 | 의미 | 설명 |
|---|---|---|
-z | Zero I/O mode | 연결만 확인하고 데이터 전송 없음 |
-v | Verbose | 상세 결과 출력 |
-u | UDP | UDP 프로토콜 사용 (기본값은 TCP) |
-w N | Timeout | N초 후 연결 시도 중단 |
-l | Listen | 서버 모드, 해당 포트에서 수신 대기 |
포트 범위 스캔:
nc -zv 192.168.1.1 20-25
20번부터 25번까지 순서대로 스캔합니다.
nc는 TCP와 UDP를 모두 지원하므로 DNS(53/UDP), NTP(123/UDP) 등 UDP 서비스 점검에도 활용됩니다.
nc 주요 사용 패턴
# TCP 포트 단일 스캔
nc -zv 192.168.1.10 80
# UDP 포트 스캔
nc -zv -u 8.8.8.8 53
# 포트 범위 스캔 (20-80번)
nc -zv 10.0.0.1 20-80
# 타임아웃 3초로 빠른 확인
nc -zv -w 3 192.168.1.10 443
# 여러 포트를 한 번에 확인
for port in 22 80 443 3306 6379; do
nc -zv -w 2 192.168.1.10 $port 2>&1
done
nc 연결 결과 해석
# 성공
$ nc -zv 192.168.1.10 80
Connection to 192.168.1.10 80 port [tcp/http] succeeded!
# 실패 (Refused)
$ nc -zv 192.168.1.10 9999
nc: connect to 192.168.1.10 port 9999 (tcp) failed: Connection refused
# 실패 (Timeout)
$ nc -zv -w 5 10.0.0.1 8080
nc: connect to 10.0.0.1 port 8080 (tcp) failed: Connection timed out
nc의 핵심 기능을 실습합니다.
1단계: 로컬 포트 스캔
# SSH 포트 확인
nc -zv localhost 22
# 흔한 서비스 포트들을 한 번에 확인
for port in 22 80 443 3306 5432 6379 8080; do
result=$(nc -zv -w 2 localhost $port 2>&1)
echo "Port $port: $result"
done
2단계: nc로 임시 TCP 서버 열기
터미널 A (서버 역할):
nc -l 9000
터미널 B (클라이언트 역할):
nc localhost 9000
이후 어느 쪽에서든 텍스트를 입력하면 반대편으로 전송됩니다. 가장 단순한 양방향 채팅입니다.
3단계: nc로 파일 전송 테스트
터미널 A (수신측):
nc -l 9001 > received_file.txt
터미널 B (송신측):
echo "Hello from nc file transfer" | nc -w 3 localhost 9001
터미널 A에서 received_file.txt 내용 확인:
cat received_file.txt
4단계: UDP 포트 확인
# DNS 서버 UDP 53 포트 확인
nc -zv -u 8.8.8.8 53
# NTP 서버 UDP 123 포트 확인
nc -zv -u pool.ntp.org 123
Connection Refused vs Connection Timeout 심층 분석
이 두 오류를 정확히 구분하는 것이 빠른 장애 원인 파악의 핵심입니다.
두 오류의 원인과 해결 방향
Connection Refused 발생 흐름:
클라이언트 → SYN → 방화벽(허용) → 서버 OS
서버 OS: "이 포트에 LISTEN 중인 소켓이 없다"
서버 OS → RST → 클라이언트
결과: 즉시 "Connection refused"

원인: 데몬(서비스)이 실행 중이지 않거나, 잘못된 포트로 LISTEN 중이거나, 서비스가 크래시됨
해결 방향:
# 서비스 상태 확인
systemctl status nginx
# 또는
ps aux | grep nginx
# 실제로 어느 포트에서 LISTEN 중인지 확인
ss -tlnp | grep nginx
Connection Timeout 발생 흐름:
클라이언트 → SYN → 방화벽(DROP) → 패킷 소멸
클라이언트: "응답이 없다... 기다린다..."
일정 시간 후: "Connection timed out"
원인: iptables DROP 규칙, AWS Security Group 미허용, 하드웨어 방화벽 ACL, 라우팅 경로 없음
해결 방향:
# iptables 규칙 확인
sudo iptables -L -n -v | grep DROP
# 클라우드 환경이면 Security Group / 방화벽 정책 확인
# traceroute로 어느 구간에서 패킷이 막히는지 확인
traceroute 목적지IP
REJECT vs DROP 차이: 방화벽 정책이 DROP이면 Timeout, REJECT이면 즉시 "Connection refused" 또는 "No route to host"가 반환됩니다. REJECT는 거부 패킷을 돌려보내고, DROP은 무응답으로 패킷을 버립니다.
실제 방화벽 동작을 재현하여 두 오류의 차이를 체감합니다.
사전 준비: 테스트용 서비스 실행
# Python으로 8080 포트에 임시 서버 실행
python3 -m http.server 8080 &
SERVER_PID=$!
echo "서버 PID: $SERVER_PID"
시나리오 1: 정상 연결
nc -zv localhost 8080
# 예상: Connection succeeded
시나리오 2: 서비스 중지 → Connection Refused
이 명령은 프로세스를 종료해 연결 중인 사용자나 배치 작업을 중단시킬 수 있습니다. PID와 프로세스 이름이 목표 서비스인지 확인한 뒤 실행하세요.
kill $SERVER_PID
nc -zv localhost 8080
# 예상: Connection refused (서비스 없음)
시나리오 3: iptables DROP → Connection Timeout
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 서비스 재시작
python3 -m http.server 8080 &
SERVER_PID=$!
# DROP 규칙 추가
sudo iptables -I INPUT -p tcp --dport 8080 -j DROP
# Timeout 확인 (3초 타임아웃으로 빠르게)
nc -zv -w 3 localhost 8080
# 예상: Connection timed out
# DROP 규칙 제거
sudo iptables -D INPUT -p tcp --dport 8080 -j DROP
# 정리
kill $SERVER_PID
시나리오 4: iptables REJECT → 즉시 거부
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
python3 -m http.server 8080 &
SERVER_PID=$!
# REJECT 규칙 추가
sudo iptables -I INPUT -p tcp --dport 8080 -j REJECT
# 즉시 거부 확인
nc -zv localhost 8080
# 예상: Connection refused (REJECT이므로 즉시 응답)
sudo iptables -D INPUT -p tcp --dport 8080 -j REJECT
kill $SERVER_PID
실전 트러블슈팅 시나리오
상황: 개발팀이 신규 Node.js 앱을 서버에 배포했지만 외부에서 http://서버IP:3000으로 접속이 안 됩니다.
1단계: 서버 내부에서 포트 확인
# 서버 내부에서 로컬호스트로 접속 테스트
nc -zv localhost 3000
결과: Connection succeeded → 앱은 실행 중
2단계: 외부에서 접속 테스트
# 다른 서버나 PC에서 실행
nc -zv 서버IP 3000
결과: Connection timed out → 방화벽 문제
3단계: iptables 확인
sudo iptables -L INPUT -n -v
# 3000번 포트 허용 규칙이 없음을 확인
4단계: 방화벽 규칙 추가
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
sudo iptables -A INPUT -p tcp --dport 3000 -j ACCEPT
# 또는 firewalld 사용 환경이라면:
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload
5단계: 재확인
nc -zv 서버IP 3000
# 예상: Connection succeeded
핵심 교훈: 내부에서는 되는데 외부에서 안 된다면, 먼저 방화벽(iptables, firewalld, Security Group)을 의심하세요.
상황: 애플리케이션 로그에 ECONNREFUSED 10.0.1.5:5432 에러가 반복됩니다.
1단계: 포트 연결 테스트
nc -zv 10.0.1.5 5432
결과: Connection refused
2단계: DB 서버에서 PostgreSQL 상태 확인
# DB 서버에 SSH 접속 후
systemctl status postgresql
결과: Active: failed → PostgreSQL이 죽어있음!
3단계: 로그 확인
journalctl -u postgresql -n 50
# 또는
tail -50 /var/log/postgresql/postgresql-14-main.log
4단계: PostgreSQL 재시작
이 명령은 실행 중인 서비스 상태를 바꿔 순간적인 중단이나 설정 반영 실패를 만들 수 있습니다. 운영 트래픽 영향과 재시작 후 확인 명령을 먼저 준비하세요.
systemctl start postgresql
systemctl status postgresql
5단계: 포트 재확인
nc -zv 10.0.1.5 5432
# 예상: Connection succeeded
추가 확인: PostgreSQL이 올바른 주소에서 LISTEN 중인지 확인
# postgresql.conf에서 listen_addresses 확인
grep listen_addresses /etc/postgresql/14/main/postgresql.conf
# 'localhost'만 있다면 외부 연결 불가 → '*' 또는 특정 IP로 변경 필요
핵심 교훈: Connection Refused는 "서비스가 없다"는 뜻입니다. 서비스 상태와 LISTEN 주소/포트 설정을 함께 확인하세요.
포트 점검 체크리스트
장애 발생 시 포트 레이어를 체계적으로 점검하는 표준 절차입니다.
#!/bin/bash
# port-check.sh - 포트 통신 종합 점검 스크립트
TARGET_HOST="${1:-localhost}"
TARGET_PORT="${2:-80}"
TIMEOUT=5
echo "===== 포트 통신 점검 시작 ====="
echo "대상: ${TARGET_HOST}:${TARGET_PORT}"
echo ""
# 1. DNS 해석 확인
echo "[1] DNS 해석 확인"
if host "${TARGET_HOST}" > /dev/null 2>&1; then
RESOLVED_IP=$(host "${TARGET_HOST}" | awk '/has address/ {print $4}' | head -1)
echo " 성공: ${TARGET_HOST} → ${RESOLVED_IP}"
else
echo " 실패: DNS 해석 불가"
fi
echo ""
# 2. L3 ping 확인
echo "[2] L3 ping 확인 (ICMP)"
if ping -c 3 -W 2 "${TARGET_HOST}" > /dev/null 2>&1; then
echo " 성공: ICMP 응답 있음"
else
echo " 실패 또는 ICMP 차단됨 (ping 차단은 정상일 수 있음)"
fi
echo ""
# 3. L4 TCP 포트 확인
echo "[3] L4 TCP 포트 확인 (nc)"
NC_RESULT=$(nc -zv -w "${TIMEOUT}" "${TARGET_HOST}" "${TARGET_PORT}" 2>&1)
if echo "${NC_RESULT}" | grep -q "succeeded"; then
echo " 성공: 포트 ${TARGET_PORT} OPEN"
elif echo "${NC_RESULT}" | grep -q "refused"; then
echo " 실패: Connection Refused (서비스 미실행 또는 잘못된 포트)"
else
echo " 실패: Connection Timeout (방화벽 DROP 의심)"
fi
echo ""
echo "===== 점검 완료 ====="
사용법:
chmod +x port-check.sh
./port-check.sh google.com 443
./port-check.sh 192.168.1.10 3306
핵심 정리
| 도구 | 주용도 | 프로토콜 | 특징 |
|---|---|---|---|
telnet | 포트 연결 확인, HTTP 수동 테스트 | TCP만 | 대부분의 시스템에 기본 설치 |
nc -zv | 포트 스캔, 범위 스캔 | TCP + UDP | 더 유연하고 스크립트에 적합 |
nc -l | 임시 서버, 연결 수신 대기 | TCP + UDP | 반대편 연결 테스트에 유용 |
오류 메시지 요약:
Connection refused= 패킷 도달 O, 서비스 없음 → 데몬 상태 확인Connection timed out= 패킷 도달 X → 방화벽/라우팅 확인Connection succeeded= L4 통신 정상 → 그 위 계층(앱, 인증) 확인