리눅스 ss 명령어 사용법 - 포트 확인과 netstat 대체 실전 예제
이 명령어를 언제 쓰는가
애플리케이션이 Address already in use 로 뜨지 않을 때, 서비스가 8080 에 떠 있다는데 밖에서 안 붙을 때, DB 커넥션이 새고 있는 것 같을 때 ss를 친다. 소켓 상태를 커널에서 직접 읽어 어떤 포트를 누가 잡고 있고, 지금 몇 개의 연결이 어떤 상태인지 보여준다.
예전에는 netstat을 썼지만 RHEL 8 이후로는 net-tools 패키지가 기본 설치되지 않아 netstat 이 아예 없는 서버가 흔하다. 지금 리눅스에서 이 역할은 iproute2 의 ss 가 맡는다. 소켓 수가 수만 개인 서버에서는 netstat 보다 눈에 띄게 빠르다.
기본 형식
ss [옵션] [필터식]
- 옵션 — 프로토콜(
-t,-u), 상태(-l,-a), 표시 방식(-n,-p)을 고른다. 보통 묶어서-tlnp처럼 쓴다. - 필터식 —
state established,dport = :3306처럼 조건을 붙여 결과를 줄인다. 괄호나 공백이 들어가면 따옴표로 감싼다.
자주 쓰는 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
-t | TCP 소켓만 | ss -t |
-u | UDP 소켓만 | ss -u -a |
-l | LISTEN 상태만 | ss -tl |
-a | LISTEN 과 연결된 소켓 모두 | ss -ta |
-n | 포트·주소를 숫자로. DNS 조회를 하지 않아 빠르다 | ss -tn |
-p | 소켓을 쥔 프로세스 표시(root 필요) | sudo ss -tlnp |
-s | 소켓 개수 요약 | ss -s |
-i | TCP 내부 정보(rtt, cwnd, 재전송) | ss -tin |
-4 / -6 | IPv4 / IPv6 만 | ss -4tlnp |
-o | 타이머 정보(keepalive, timewait 잔여시간) | ss -tno |
실전 예제
1. 열려 있는 포트와 그 주인을 한 번에 본다. 서버에 처음 들어갔을 때 가장 먼저 치는 명령이다.
sudo ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1180,fd=6))
LISTEN 0 128 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=942,fd=22))
LISTEN 0 100 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=810,fd=3))
Local Address 를 반드시 본다. 위 MariaDB 는 127.0.0.1:3306 이므로 다른 서버에서는 절대 붙을 수 없다. 방화벽을 아무리 열어도 안 된다. 원격 접속이 필요하면 bind-address 설정을 고쳐야 한다.
2. 포트를 이미 누가 쓰고 있는지 확인한다. 기동 실패 로그에 Address already in use 가 찍혔을 때다.
sudo ss -tlnp 'sport = :8080'
3. DB 커넥션 수를 세어 누수를 확인한다. 커넥션 풀이 반환되지 않으면 이 숫자가 계속 오른다.
ss -Htn state established '( dport = :3306 )' | wc -l
-H(헤더 생략)를 빼면 헤더 줄까지 세어 결과가 실제보다 1 크게 나온다.
어느 애플리케이션 서버가 많이 물고 있는지 보려면 상대 IP 로 집계한다.
ss -Htn state established '( sport = :3306 )' | awk '{split($4,a,":"); print a[1]}' | sort | uniq -c | sort -rn
상대 주소가 $5 가 아니라 $4 인 이유가 있다. state established 처럼 상태를 하나로 못 박으면 ss 가 State 열을 통째로 빼고 출력하기 때문이다. 반면 -l 은 내부적으로 LISTEN 과 CLOSE 두 상태를 잡아서 State 열이 남는다. 열 번호를 쓰기 전에 필터를 건 그대로 한 번 실행해 눈으로 세어본다.
4. 소켓이 어떤 상태에 몰려 있는지 요약한다. TIME-WAIT 이 수만 개면 포트 고갈을 의심한다.
ss -s
Total: 412
TCP: 1183 (estab 96, closed 1042, orphaned 0, timewait 1041)
Transport Total IP IPv6
RAW 0 0 0
UDP 8 6 2
TCP 141 133 8
5. 특정 서버와의 연결만 추린다. 어느 백엔드와 통신이 끊겼는지 확인할 때 쓴다.
sudo ss -tnp dst 10.0.1.30
함정과 주의점
-p는 root 가 아니면 남의 프로세스를 보여주지 않는다. 일반 사용자로 ss -tlnp 를 치면 Process 칸이 비어 있어 주인 없는 포트처럼 보인다. 포트를 잡은 범인을 찾을 때는 반드시 sudo를 붙인다.
0.0.0.0:포트와 127.0.0.1:포트는 하늘과 땅 차이다. 전자는 모든 인터페이스에서 받고, 후자는 서버 자기 자신에서만 받는다. 서버 안에서 curl 이 되는데 밖에서 안 된다는 상황의 절반은 방화벽이 아니라 이 바인딩 주소 문제다. [::]:80 으로만 떠 있으면 IPv6 만 받고 있는 것이므로 이것도 확인한다.
필터식은 따옴표로 감싼다. ss -tn state established ( dport = :80 ) 처럼 치면 셸이 괄호를 서브셸로 해석해 문법 오류가 난다. 괄호와 공백이 있는 조건은 통째로 작은따옴표 안에 넣는다.
ss 는 리눅스 전용이다. macOS 와 BSD 에는 없다. 맥에서는 netstat -an 이나 lsof -nP -iTCP -sTCP:LISTEN 을 쓴다. 리눅스 서버용으로 짠 점검 스크립트를 맥에서 돌리면 여기서 걸린다.
함께 보면 좋은 명령어
lsof— 소켓뿐 아니라 그 프로세스가 연 파일까지 같이 본다. 포트 주인을 파고들 때 쓴다.curl— 포트가 열려 있는 것과 애플리케이션이 정상 응답하는 것은 다른 문제다. ss 다음에 확인한다.ip— 인터페이스와 라우팅을 본다. 바인딩 주소 문제를 추적할 때 함께 쓴다.