문제 인식
운영 환경의 NLB(Network Load Balancer)에 연결된 타겟 그룹들을 확인하던 중, 일부 서비스의 타겟이 Unhealthy 상태인 것을 발견했습니다.
실제 서비스 통신은 정상적으로 되고 있었지만, Health Check가 실패하고 있어 로드밸런서가 타겟을 비정상으로 판단하는 상황이었습니다.

문제를 두 가지 케이스로 나누어 분석했습니다.
해결 과정 1 — 보안 그룹 누락
원인 확인
첫 번째 타겟 그룹(포트 16443)의 경우, 해당 포트에 대해 NLB 네트워크 대역의 보안 그룹 인바운드 규칙이 열려있지 않은 상태였습니다.
NLB는 클라이언트 IP를 보존하는 특성이 있어, 타겟 인스턴스의 보안 그룹에서 NLB 서브넷 CIDR 또는 클라이언트 IP 대역을 허용해야 합니다.
조치
보안 그룹에 해당 포트(16443)에 대한 NLB 네트워크 대역 인바운드 규칙을 추가했습니다.

결과
보안 그룹 추가 후 타겟이 Healthy로 전환되었습니다.

해결 과정 2 — Health Check 포트 불일치
증상
두 번째 타겟 그룹(포트 25080)의 경우, 보안 그룹을 열어줘도 여전히 Unhealthy 상태가 지속되었습니다.

NLB 설정 확인
AWS CLI로 타겟 헬스를 조회한 결과, HealthCheckPort가 40000으로 설정되어 있었습니다. 실제 트래픽 포트(25080)와 완전히 다른 포트였습니다.
$ aws elbv2 describe-target-health \
--target-group-arn arn:aws:elasticloadbalancing:ap-northeast-2:...:targetgroup/...
응답에서 확인된 핵심 정보:
- Port: 11080 (트래픽 포트)
- HealthCheckPort: 40000 (상태 검사 포트)
- State: unhealthy
- Reason: Target.FailedHealthChecks
서버 내 포트 확인
실제 인스턴스에 접속하여 telnet으로 포트 상태를 확인했습니다.
트래픽 포트 (11080) — 정상 연결:

$ telnet localhost 11080
Connected to localhost.
Health Check 포트 (40000) — 연결 거부:

$ telnet localhost 40000
Connection refused
원인이 명확해졌습니다. Health Check 포트(40000)가 서버에서 실제로 리스닝하지 않는 포트였기 때문에, NLB가 타겟을 Unhealthy로 판단한 것이었습니다.
개발 환경 비교
개발 환경의 LB를 확인해보니, 개발 LB는 별도의 Health Check 포트가 지정되어 있지 않았고(트래픽 포트를 그대로 사용), 모든 인스턴스가 Healthy 상태였습니다.
이를 통해 Health Check 포트를 트래픽 포트로 변경하면 문제가 해결될 것이라 판단했습니다. 상태 검사 포트 변경은 서비스 트래픽에 영향을 주지 않으므로 운영 환경에 바로 적용했습니다.
운영 환경 적용
타겟 그룹의 상태 검사 설정에서 Health Check 포트를 트래픽 포트로 변경했습니다.

결과: 모든 타겟이 Healthy로 전환되었습니다. 동일한 설정을 관련 타겟 그룹 전체에 적용하고, 보안 그룹도 함께 정리했습니다.
추가 발견 — 열려있지 않은 포트
같은 점검 과정에서 포트 12085를 사용하는 타겟 그룹도 Unhealthy 상태인 것을 확인했습니다.


해당 포트 역시 서버에서 리스닝하지 않는 상태였으며, 동일한 방식으로 Health Check 포트를 실제 서비스 포트로 변경하여 해결했습니다.
참고: NLB vs ALB
이번 이슈를 다루면서 NLB와 ALB의 차이점도 정리했습니다.
| 항목 | NLB | ALB |
|---|---|---|
| 계층 | L4 (TCP/UDP) | L7 (HTTP/HTTPS) |
| 고정 IP | EIP 할당 가능 | 불가 |
| Health Check | TCP / HTTP | HTTP / HTTPS |
| 주요 용도 | 고성능, 고정 IP 필요 시 | 경로 기반 라우팅, HTTP 기능 |
NLB는 EIP를 할당받아 사용할 수 있다는 장점이 있어, 상황에 따라 NLB를 ALB 앞에 두고 사용하는 아키텍처도 적용됩니다.

정리
| 케이스 | 원인 | 해결 |
|---|---|---|
| 타겟 그룹 A (16443) | 보안 그룹에 NLB 대역 미허용 | 인바운드 규칙 추가 |
| 타겟 그룹 B (25080) | Health Check 포트(40000)가 서버에서 미리스닝 | Health Check 포트를 트래픽 포트로 변경 |
| 타겟 그룹 C (12085) | 동일 — 미리스닝 포트로 Health Check | 동일 조치 |
NLB 타겟 그룹이 Unhealthy일 때 체크할 순서:
- 보안 그룹: NLB 서브넷 CIDR에서 타겟 포트로의 인바운드가 열려 있는지
- Health Check 포트: 실제 서비스가 리스닝하는 포트와 일치하는지
- 서버 내 포트 확인:
telnet localhost {port}로 실제 리스닝 여부 확인
"통신은 되는데 Unhealthy"라는 상황은 대부분 Health Check 설정과 실제 서버 상태의 불일치에서 발생합니다.