주소·서브넷·게이트웨이 · 헤어핀 NAT · 이론
안에서 밖의 주소로 나를 부를 때
한 줄 요약
집 안에서 내 공인 도메인으로 접속하면 패킷이 공유기까지 갔다가 되돌아와야 하는데, 많은 공유기가 그걸 못 한다. 이것을 헤어핀 NAT(또는 NAT 루프백)이라 한다.
왜 이게 필요했나
집에 서버를 두고 labhub.hopto.org 로 열어 두면 밖에서는 잘 되는데 집 안 노트북에서만 안 되는 일이 흔하다. 원인은 이렇다.
1. 노트북(192.168.0.10)이 labhub.hopto.org 를 조회한다 → 공인 IP(1.2.3.4)가 나온다
2. 노트북이 1.2.3.4 로 패킷을 보낸다 → 자기 서브넷 밖이므로 공유기로 간다
3. 공유기는 1.2.3.4 가 자기 자신임을 알아채고, 포트포워딩 규칙에 따라 192.168.0.20(서버)으로 목적지를 바꾼다
4. 서버가 응답한다. 그런데 응답의 출발지는 192.168.0.20 이고 노트북은 1.2.3.4 에서 올 응답을 기다리고 있다
5. 노트북은 그 응답을 "내가 보낸 적 없는 연결" 로 보고 버린다
패킷이 공유기에서 U턴한다고 해서 헤어핀(머리핀)이다. 해결하려면 공유기가 목적지뿐 아니라 출발지도 자기 주소로 바꿔야 한다(SNAT 을 함께 건다). 그러면 서버는 공유기에게 응답하고, 공유기가 노트북에게 되돌려 준다.
어떻게 동작하나
증상을 확인하는 방법은 단순하다.
# 밖에서는 되는데 안에서만 안 되는가?curl -sI https://labhub.hopto.org # 집 안에서 → 타임아웃curl -sI http://192.168.0.20 # 사설 주소로 직접 → 됨내부 주소로는 되고 도메인으로는 안 되면 헤어핀이다.
어떻게 푸는가
공유기가 헤어핀을 지원하면 켜면 된다(설정 이름이 제조사마다 다르다 — NAT Loopback, Hairpin NAT, 내부 접속 허용).
지원하지 않으면 스플릿 호라이즌 DNS 가 정석이다. 같은 도메인을 안에서 물으면 사설 주소를, 밖에서 물으면 공인 주소를 답하게 한다.
- 내부 DNS(예: 라우터의 DNS, Pi-hole, CoreDNS)에
labhub.hopto.org → 192.168.0.20을 넣는다 - 그러면 집 안 기기는 애초에 공유기까지 가지 않는다
이 방식이 더 좋은 이유가 하나 더 있다. 헤어핀은 트래픽을 공유기까지 왕복시키므로 집 안 통신인데 공유기 성능에 묶인다. 스플릿 DNS 는 스위치 안에서 끝난다.
흔한 착각
hosts 파일로 때우는 것. 노트북 한 대는 되지만 휴대폰과 태블릿은 안 된다. DNS 계층에서 푸는 것이 맞다.
공인 IP 가 바뀌면 끝난다는 착각. DDNS 를 쓰면 공인 IP 는 따라가지만, 내부 DNS 에 박아 둔 사설 주소는 서버를 옮기면 손으로 고쳐야 한다. 두 곳을 관리해야 한다는 사실을 기억해 둔다.
실무에서 진짜 중요한 것
쿠버네티스에도 같은 문제가 있다. 파드가 자기 서비스의 외부 주소(LoadBalancer IP)로 자기 자신을 부르면 같은 헤어핀 상황이 된다. externalTrafficPolicy: Local 을 쓰면 노드가 SNAT 을 하지 않아 이 경우 응답이 돌아오지 못할 수 있다.
그래서 클러스터 안에서는 항상 서비스 이름(svc.namespace.svc.cluster.local)으로 부른다. 외부 주소로 자기를 부르지 않는다 — 이 한 줄이 헤어핀 문제의 절반을 없앤다.