공인 IP는 게이트웨이 한 대뿐인데 내부 여러 서버로 트래픽을 나눠야 하거나, 80번으로 들어온 요청을 내부 8080 컨테이너로 넘기고 싶을 때가 있습니다. 이때 쓰는 것이 NAT 포트포워딩(DNAT)입니다. 패킷의 목적지 주소를 커널이 바꿔치기합니다.
증상 — 왜 그냥은 안 닿나
외부에서 게이트웨이의 특정 포트로 보낸 패킷은, 명시적으로 전달 규칙이 없으면 내부 호스트로 가지 않습니다. 또 리눅스는 기본적으로 받은 패킷을 다른 인터페이스로 넘기지 않습니다(IP 포워딩 비활성).
진단 — 포워딩이 켜져 있나
sysctl net.ipv4.ip_forward # 0이면 포워딩 꺼짐
iptables -t nat -L -n -v # 현재 NAT 규칙
ip_forward가 0이면 라우팅 자체가 안 되므로 먼저 켭니다.
sysctl -w net.ipv4.ip_forward=1
영구 반영은 /etc/sysctl.conf에 net.ipv4.ip_forward = 1을 적고 sysctl -p를 실행합니다.
단계 — DNAT 규칙 설정
들어온 요청 목적지를 내부 주소로 바꾸는 것은 PREROUTING 체인의 DNAT, 돌아가는 경로를 위한 주소 변환은 POSTROUTING의 MASQUERADE입니다.
- 외부 8080 요청을 내부 192.168.1.10:80으로 전달
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
-j DNAT --to-destination 192.168.1.10:80
- 응답이 게이트웨이를 거쳐 돌아오도록 마스커레이드
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.10 --dport 80 \
-j MASQUERADE
필터 테이블의 FORWARD 기본 정책이 DROP이면 NAT 규칙만으로는 패킷이 통과하지 않습니다. 내부 서버와 외부 클라이언트의 새 연결을 허용하고, 기존 연결의 응답을 먼저 허용해야 합니다(운영 방화벽 정책에 맞게 출발지·인터페이스를 제한하세요).
# ⚠️ 아래는 격리된 실습망 예시입니다. 운영에서는 ruleset 백업·OOB 복구 경로를 먼저 확보하세요.
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 \
-m conntrack --ctstate NEW -j ACCEPT
| 체인 | 시점 | 역할 |
|---|---|---|
| PREROUTING | 라우팅 결정 전 | 목적지 주소 변경(DNAT) |
| POSTROUTING | 인터페이스로 나가기 직전 | 출발지 주소 변경(SNAT/MASQUERADE) |
규칙의 목적지·포트 표기에서 부등호 같은 특수문자는 쓰지 않으며, --to-destination은 IP:포트 형식입니다.
확인 체크리스트
sysctl net.ipv4.ip_forward # 1인지
iptables -t nat -L PREROUTING -n -v # DNAT 규칙·패킷 카운터
curl http://게이트웨이IP:8080/ # 외부에서 실제 도달 테스트
conntrack -L | grep 192.168.1.10 # 변환된 연결 추적(있으면)
규칙은 넣었는데 안 닿는다면 십중팔구 ip_forward가 꺼졌거나, 내부 서버의 응답이 게이트웨이로 돌아오는 경로(라우팅·SNAT)가 없는 경우입니다. -L -n -v의 패킷 카운터가 0이면 규칙에 트래픽이 아예 안 걸린 것입니다.
NAT·iptables 체인을 직접 만들고 패킷이 어떻게 변환되는지 추적하는 실습은 네트워크 트랙에서 회원가입 없이 무료로 할 수 있습니다.