SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-21

Linux 포트 개방 여부 확인 및 연결 테스트 방법

ss 명령어로 서버 내부 리스닝 상태를 확인하고 nc나 nmap으로 외부 연결을 테스트하는 방법을 설명합니다. 포트가 닫혀 있을 때와 차단되었을 때의 응답 차이를 이해하고 네트워크 문제를 정확하게 진단하십시오.

Linux에서 포트 개방 여부 확인: 올바른 질문 선택하기

Linux에서 포트가 열려 있는지 확인하려면 먼저 어떤 질문을 던지는지 결정해야 합니다. "열려 있다"는 의미는 확인하는 위치에 따라 다르기 때문입니다. 서버 내부에서 "열려 있다"는 것은 프로세스가 해당 포트에 바인딩되어 대기 중임을 의미합니다. 다른 기기에서 볼 때 "열려 있다"는 것은 패킷이 해당 프로세스에 도달하여 응답을 받았음을 의미합니다. 응답이 없다면, 어떤 장비가 패킷을 차단했는지 확인하는 것이 핵심입니다. sudo ss -ltnp은 첫 번째 질문에 대한 답을 줍니다. nc -z 또는 nmap는 두 번째 질문에 대한 답을 줍니다. 방화벽 카운터와 tcpdump은 세 번째 질문을 해결합니다.

잘못된 확인 방법을 사용하면 시간을 낭비하게 됩니다. 서버 내부에서 수행하는 테스트는 제공업체의 네트워크 방화벽을 거치지 않습니다. 해당 필터는 서버 외부에서 작동하기 때문입니다. 포트 번호가 아직 생소하다면, Linux에서 포트와 소켓이 작동하는 방식에서 이 가이드의 기반이 되는 모델을 확인하십시오.

이 서버에서 리스닝 중인 서비스는 무엇인가? ss 출력 확인하기

ss은 iproute2 패키지에 포함되어 있으므로 현재 사용 중인 모든 배포판에 기본으로 설치되어 있습니다. netstat은 net-tools 패키지에 포함되어 있는데, Ubuntu는 수년 전부터 이를 기본으로 설치하지 않으므로 netstat -tulpn를 입력하면 종종 netstat: command not found이라는 응답이 돌아옵니다. ss 사용법을 익혀 불필요한 수고를 피하십시오.

sudo ss -ltnp

-l는 리스닝 중인 소켓만 보여줍니다. -t은 목록을 TCP로 제한합니다. -n는 이름을 해석하는 대신 숫자로 출력하므로 명령이 즉시 반환됩니다. -p는 소유 프로세스 이름을 표시하며, 이를 위해서는 root 권한이 필요합니다. sudo 없이 실행하면 본인 소유가 아닌 모든 프로세스의 Process 열이 비어 있게 됩니다. UDP를 확인하려면 -t 대신 -u을 사용하십시오.

State  Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
LISTEN 0      4096   127.0.0.53%lo:53    0.0.0.0:*   users:(("systemd-resolve",pid=612,fd=14))
LISTEN 0      128    0.0.0.0:22          0.0.0.0:*   users:(("sshd",pid=921,fd=3))
LISTEN 0      511    127.0.0.1:8080      0.0.0.0:*   users:(("node",pid=1442,fd=19))
LISTEN 0      128    [::]:22             [::]:*      users:(("sshd",pid=921,fd=4))

Local Address 열은 모든 것을 결정하지만, 많은 사용자가 이를 대충 훑고 지나갑니다.

  • 0.0.0.0:22는 서버의 모든 IPv4 주소를 의미하므로, 방화벽이 허용한다면 외부에서 접근할 수 있습니다.
  • [::]:22은 IPv6에서 동일한 의미를 갖습니다.
  • 127.0.0.1:8080은 루프백 전용을 의미합니다. 이 서버 외부에서는 그 무엇도 접근할 수 없습니다.
  • 10.20.0.5:5432는 특정 인터페이스 주소 하나만을 의미하며, 사설 네트워크 구성에서 흔히 볼 수 있습니다.
  • Process 열이 비어 있다면 보통 프로세스가 없는 것이 아니라 sudo 권한이 부족한 것입니다.

특정 포트를 확인하려면 전체 목록을 grep하지 말고 ss 내부에서 필터링하십시오.

sudo ss -ltnp 'sport = :8080'
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
sudo fuser 8080/tcp

세 명령 모두에서 출력이 없다면 해당 포트를 점유한 프로세스가 없는 것입니다. 서비스가 중지되었거나, 시작에 실패했거나, 다른 곳에서 리스닝 중일 수 있습니다. 방화벽 규칙을 건드리기 전에 systemctl status <unit>journalctl -u <unit> -n 50을 먼저 확인하십시오.

Local Address에 127.0.0.1을 설정하면 발생하는 문제

127.0.0.1에 바인딩된 소켓은 다른 호스트에서 접근할 수 없으며, 방화벽 규칙을 변경해도 해결되지 않습니다. 커널은 127.0.0.0/8로 향하는 패킷을 루프백 인터페이스로만 라우팅하며, 실제 네트워크 카드로 들어온 해당 목적지 주소의 패킷은 비정상적인 패킷(martian)으로 간주되어 폐기됩니다. 따라서 프로세스는 실행 중이고 ss 명령어로 리스닝 상태를 확인할 수 있으며 ufw allow 8080 명령어도 성공을 보고하지만, 노트북에서 시도하는 연결은 여전히 실패합니다. 패킷이 공인 IP 주소에 도달해도 해당 주소에 바인딩된 소켓이 없으므로 커널이 TCP 리셋을 응답하기 때문에, 연결은 즉시 Connection refused 오류와 함께 실패합니다.

많은 프로그램이 의도적으로 루프백에 바인딩하며, 데이터베이스나 관리 인터페이스의 경우 이것이 올바른 기본값입니다. 여기에는 두 가지 정석적인 해결 방법이 있습니다. 프로그램 자체 설정에서 바인딩 주소를 변경하고(postgresql.conflisten_addresses, redis.confbind, 또는 애플리케이션이 사용하는 호스트 인자) 방화벽을 개방하는 방법이 있습니다. 아니면 루프백 설정을 유지한 채 nginx 리버스 프록시나 노트북에서 연결하는 SSH 터널과 같은 다른 수단을 통해 접근할 수도 있습니다.

ssh -L 8080:127.0.0.1:8080 user@203.0.113.10

Docker 역시 publish 플래그에서 동일한 구분을 사용합니다. -p 8080:80800.0.0.0에 바인딩하여 컨테이너를 인터넷에 노출합니다. -p 127.0.0.1:8080:8080은 루프백에 바인딩하여 로컬에서만 접근 가능하도록 제한합니다.

다른 머신에서 Linux의 포트가 열려 있는지 확인하는 방법

이 테스트는 다른 네트워크에서 실행해야 합니다. 서버 내부에서 수행하는 테스트는 루프백 경로가 정상인지 확인하는 것일 뿐입니다. 서버에서 자신의 공인 IP로 접속하는 것조차 제공자의 네트워크 방화벽을 거치지 않는데, 해당 필터는 VPS 외부에서 작동하기 때문입니다.

nc -zv -w 3 203.0.113.10 443

-z는 데이터를 전송하지 않고 연결 후 즉시 종료합니다. -w 3은 3초 뒤에 포기하며, 이 플래그는 중요합니다. 타임아웃이 없으면 패킷이 드롭될 경우 커널이 중단하기 전까지 클라이언트가 2분 넘게 SYN 재시도를 반복하기 때문입니다. 성공 시 결과는 다음과 같습니다.

Connection to 203.0.113.10 443 port [tcp/https] succeeded!

도구가 없다면(nc: command not found), Debian이나 Ubuntu에서는 netcat-openbsd를 설치하십시오. 또는 별도의 패키지가 필요 없는 bash의 내장 네트워크 리다이렉션을 사용해도 됩니다.

timeout 3 bash -c '</dev/tcp/203.0.113.10/443' && echo open || echo "no answer"

해당 문법은 bash 기능이므로 bash으로 실행해야 합니다. Debian과 Ubuntu의 /bin/sh는 dash이며, 이는 /dev/tcp를 지원하지 않아 경로가 존재하지 않는다는 오류를 출력합니다. 여러 포트를 확인하거나 상태를 명확히 알고 싶다면, 관리 권한이 있는 호스트를 대상으로 nmap을 사용하십시오.

sudo nmap -Pn -p 22,80,443 203.0.113.10
sudo nmap -Pn -p 1-1024 203.0.113.10

-Pn은 호스트 탐색을 건너뜁니다. 대부분의 VPS 호스트는 ICMP echo를 차단하므로, -Pn 없이는 nmap이 호스트가 다운되었다고 판단하여 아무것도 스캔하지 않습니다. nmap은 연결을 수락하고 응답하면 open을, 리셋 신호로 응답하면 closed를, 아무런 응답이 없으면 filtered을 출력합니다. 웹 서비스의 경우, 상태 코드는 전체 경로가 정상임을 증명하므로 curl -sS -o /dev/null -w '%{http_code}\n' https://example.com을 사용하면 네트워크 오류와 애플리케이션 오류를 구분할 수 있습니다.

차단된 포트에서 응답이 없고 닫힌 포트에서 즉시 거부하는 이유

즉각적인 거부. 패킷이 대상 장비에 도달했고 무언가가 응답을 보낸 경우입니다.

nc: connect to 203.0.113.10 port 443 (tcp) failed: Connection refused

두 가지 서로 다른 원인이 정확히 동일한 결과를 만듭니다. 해당 주소와 포트에 바인딩된 프로세스가 없어 커널이 TCP 리셋으로 응답했거나, 방화벽 규칙이 리셋 또는 ICMP port unreachable 메시지로 패킷을 거부한 경우입니다. 거부는 확실한 응답이며 한 번의 왕복(round trip)으로 돌아옵니다.

지연 후 타임아웃. 무언가가 패킷을 폐기(drop)했고 아무런 응답도 보내지 않은 경우입니다.

nc: connect to 203.0.113.10 port 443 (tcp) timed out: Operation now in progress

이것이 DROP 규칙이 동작하는 방식이며, 제공업체의 방화벽이나 클라우드 보안 그룹이 수행하는 방식이기도 합니다. 송신자는 패킷이 폐기된 것인지 호스트가 죽은 것인지 구분할 수 없으므로, 침묵은 폐기의 특징입니다.

증상을 보면 다음으로 무엇을 확인해야 할지 알 수 있습니다. 거부(Refused)는 패킷이 네트워크를 정상적으로 통과하고 있다는 뜻이므로 ss -ltnp로 돌아가 바인드 주소와 포트 번호를 확인하십시오. 타임아웃(Timed out)은 패킷이 폐기되고 있다는 뜻이므로 외부에서 내부로 방화벽 설정을 검토하십시오. SSH에서 거부와 타임아웃의 차이는 대부분의 사용자가 이 문제를 처음 겪게 되는 포트 22를 기준으로 동일한 내용을 다룹니다.

ufw는 의도적으로 두 가지 동작을 모두 제공합니다. ufw deny 8080은 패킷을 폐기하고, ufw reject 8080는 거부 메시지를 보냅니다. nftables에서 두 타겟은 dropreject이며, iptables에서는 -j DROP-j REJECT입니다. 기본 정책은 거의 항상 폐기(drop)이므로, 규칙이 누락되면 오류 메시지 대신 응답 지연이 발생합니다.

어떤 것이 포트를 차단하고 있는가? 외부에서 내부로 확인하기

sudo ufw status verbose
sudo iptables -L INPUT -n -v --line-numbers
sudo nft list ruleset

-v 카운터는 매우 유용한 정보입니다. 외부에서 nc 테스트를 실행한 뒤, iptables 명령을 다시 실행하여 카운터 값을 확인하십시오. 패킷 카운트가 증가하는 규칙이 바로 트래픽을 처리하고 있는 규칙입니다. 이 방법을 사용하면 추측이 아닌 증거를 바탕으로 문제를 해결할 수 있습니다.

결정적인 테스트는 서버에서 수행합니다. 외부에서 접속을 시도하는 동안 네트워크 인터페이스를 감시하십시오.

sudo tcpdump -ni any tcp port 8080

SYN 패킷은 도착하는데 SYN-ACK 응답이 나가지 않는다면, 패킷이 VPS까지 도달했으나 호스트에서 이를 폐기한 것입니다. 즉, 제공업체의 방화벽은 정상이며 로컬 규칙에 문제가 있다는 뜻입니다. 출력 결과가 전혀 없다면 패킷이 아예 도착하지 않은 것이므로, 제공업체 방화벽, 보안 그룹 설정, 또는 잘못된 IP 주소가 원인입니다. 이 한 가지 구분만으로도 대부분의 작업이 줄어듭니다.

두 가지 계층에서 불가능해 보이는 결과가 나타날 수 있습니다. 첫째, IPv6입니다. 호스트네임에 AAAA 레코드가 있으면 클라이언트가 IPv6로 접속할 수 있는데, 규칙은 IPv4만 다루고 있을 수 있습니다. 따라서 결과를 신뢰하기 전에 nc -4nc -6를 사용하여 각 프로토콜 계열을 개별적으로 테스트하십시오. VPS의 ufw 규칙과 IPv6 포트에서 이러한 불일치 문제를 다룹니다. 둘째, Docker입니다. ufw status에서 해당 포트를 거부하도록 설정했더라도, Docker로 게시된 컨테이너 포트는 인터넷에서 응답할 수 있습니다. 이는 해당 패킷이 ufw 체인에 도달하기 전에 처리되기 때문입니다. Docker가 ufw를 우회하여 포트를 게시하는 이유에 메커니즘과 해결책이 있으며, 새 VPS에 설정해야 할 기본 ufw 규칙에서 필수적인 기초 설정을 확인할 수 있습니다.

UDP 응답이 설계상 모호한 이유

UDP는 핸드셰이크 과정이 없으므로 프로브(probe)가 성공할 대상이 없습니다. nc -zu 203.0.113.10 53는 패킷이 나가는 즉시 0을 반환하며, 이는 자신의 머신이 패킷을 보냈다는 사실만 증명할 뿐 원격지에 대해서는 아무것도 증명하지 못합니다. UDP 포트가 닫혀 있으면 호스트는 일반적으로 ICMP port unreachable 메시지를 반환하지만, 커널은 다음 쓰기 작업 시에만 연결된 소켓에 해당 오류를 보고하므로 단일 패킷 프로브로는 이를 감지할 수 없습니다. 방화벽은 관례적으로 ICMP를 차단하며, 이로 인해 유일한 단서마저 사라집니다. 이것이 nmap이 대부분의 UDP 포트에 대해 open|filtered를 출력하는 이유입니다. 응답이 없는 상태는 조용히 대기 중인 열린 서비스와 필터링된 포트 모두에서 나타나는 동일한 결과이기 때문입니다.

UDP를 테스트하려면 해당 프로토콜을 직접 사용해야 합니다. DNS 서버는 dig +short @203.0.113.10 example.com에 대해 주소를 반환하거나 아무런 응답을 하지 않습니다. WireGuard 피어는 sudo wg show에서 최근 latest handshake 라인을 보여줍니다. 그다음 서버 측에서 패킷 도달 여부를 확인하십시오.

sudo tcpdump -ni any udp port 51820

클라이언트가 패킷을 보낼 때 패킷이 나타난다면 패킷은 정상적으로 도착한 것이므로, 서비스나 입력 체인(input chain)에 문제가 있는 것입니다. 패킷이 전혀 보이지 않는다면 패킷이 서버에 도달하지 못한 것입니다.

가장 빠르게 결함을 찾는 점검 목록

  1. 서버에서 sudo ss -ltnp 'sport = :8080'를 실행합니다. 출력이 없다면 아무것도 수신 대기 중이지 않은 상태이므로, 먼저 서비스를 수정해야 합니다.
  2. 출력이 있다면 Local Address 열을 확인합니다. 127.0.0.1으로 표시되어 있다면, 바인딩을 다시 설정하거나 앞에 프록시를 두기 전까지는 외부에서 접근할 수 없습니다.
  3. 다른 네트워크에서 nc -zv -w 3 <public ip> 8080을 실행합니다.
  4. 연결이 거부된다면 1단계로 돌아갑니다. 주소, 포트 또는 대상 장비가 예상과 다른 상태입니다.
  5. 타임아웃이 발생하면 패킷이 드롭되는 것입니다. 서버에서 sudo tcpdump -ni any tcp port 8080를 시작하고 테스트를 반복합니다.
  6. SYN 패킷은 도착하지만 응답이 없다면 호스트 방화벽 문제입니다. sudo iptables -L INPUT -n -v에서 카운터가 증가하는 규칙을 찾습니다.
  7. SYN 패킷 자체가 도착하지 않는다면 제공자 방화벽, 보안 그룹 또는 잘못된 IP 주소 문제입니다.

FAQ

리눅스 서버에서 열려 있는 포트를 확인하려면 어떻게 해야 합니까?

TCP는 sudo ss -ltnp를, UDP는 sudo ss -lunp를 실행하십시오. 각 행은 하나의 리스닝 소켓을 나타내며, Local Address 열을 통해 접근 가능 범위를 알 수 있습니다. 0.0.0.0[::]은 방화벽이 허용하는 모든 곳에서 접속을 수락하며, 127.0.0.1은 해당 서버 내부에서만 접속을 수락합니다. Process 열을 확인하려면 root 권한이 필요하므로 sudo와 함께 실행해야 하며, 그렇지 않으면 비어 있는 상태로 출력됩니다. ss은 iproute2 패키지의 일부로 항상 설치되어 있지만, netstat은 net-tools 패키지의 일부로 보통 설치되어 있지 않습니다.

ss 명령어로 서비스가 리스닝 중인 것을 확인했는데 왜 접속할 수 없습니까?

두 가지 일반적인 원인이 있으며, 하나의 명령어로 이를 구분할 수 있습니다. Local Address가 127.0.0.1라면 서비스가 루프백에 바인딩되어 다른 호스트에서 접근할 수 없는 상태입니다. 커널은 해당 대역을 루프백 인터페이스로만 라우팅하기 때문입니다. 만약 0.0.0.0인데도 접속이 실패한다면, 서버에서 sudo tcpdump -ni any tcp port <port>를 실행한 상태로 외부에서 접속을 시도하십시오. SYN 패킷은 도착했으나 응답이 없다면 로컬 방화벽 규칙이 패킷을 드롭하는 것입니다. 패킷 자체가 도착하지 않는다면 VPS에 도달하기 전에 차단된 것이며, 보통 제공업체의 방화벽이나 보안 그룹이 원인입니다.

접속 거부(refused)와 타임아웃(timed out)의 차이는 무엇입니까?

접속 거부는 서버로부터의 응답입니다. 패킷이 호스트에 도달하여 TCP 리셋이나 ICMP 포트 도달 불가 메시지를 받은 경우로, 해당 주소와 포트에서 리스닝 중인 서비스가 없거나 방화벽 규칙이 거부했음을 의미합니다. 타임아웃은 침묵입니다. 규칙이 패킷을 드롭하고 아무런 응답도 보내지 않았기 때문에 클라이언트는 포기할 때까지 재시도를 반복합니다. 접속 거부는 서비스와 바인딩 주소를 점검해야 함을 의미하며, 타임아웃은 방화벽을 점검해야 함을 의미합니다. 외부와 가장 가까운 방화벽부터 확인하십시오.

UDP 포트가 열려 있는지 어떻게 확인합니까?

UDP는 핸드셰이크 과정이 없으므로 일반적인 프로브로는 확실한 결과를 얻을 수 없습니다. 응답이 없는 서비스는 패킷이 드롭된 것과 동일하게 보이기 때문입니다. nc -zu는 패킷을 전송하자마자 성공을 반환하며, nmap도 같은 이유로 open|filtered 상태를 보고합니다. 대신 해당 프로토콜로 직접 통신을 시도하십시오. DNS라면 dig +short @<host> example.com을, 최근 핸드셰이크가 발생한 WireGuard 피어라면 sudo wg show을 사용합니다. 패킷이 실제로 도착하는지 확인하려면 클라이언트가 패킷을 보내는 동안 서버에서 sudo tcpdump -ni any udp port <port>를 실행하십시오.

포트 테스트를 위해 여전히 telnet host port를 사용할 수 있습니까?

TCP 연결에는 작동하며, Escape character is '^]'은 연결이 수락되었음을 의미합니다. 종료하려면 Ctrl+]을 입력한 뒤 quit를 사용하십시오. nc -z이 더 나은 도구인 이유는 두 가지입니다. 대부분의 최신 서버 이미지에는 telnet이 설치되어 있지 않으며, nc-w 플래그로 타임아웃을 설정할 수 있고 스크립트에서 테스트 가능한 종료 상태를 반환하기 때문입니다. 두 도구 모두 사용할 수 없는 환경이라면 별도의 패키지 설치가 필요 없는 timeout 3 bash -c '</dev/tcp/<host>/<port>'을 사용하십시오.