infra
Platform

모듈 맵

[Network] NAT 변환과 포트 포워딩(Port Forwarding) 작동 원리

0 / 35 완료

펼치기
0 / 35 완료0%

네트워크 트러블슈팅 · 10 / 35

[Network] NAT 변환과 포트 포워딩(Port Forwarding) 작동 원리

SNAT/DNAT 차이를 이해하고 iptables로 포트 포워딩을 구성합니다

🚨INCIDENT ALERT
HIGH

외부에서는 5.6.7.8:8080으로 접속했는데 내부 웹 서버에는 아무 요청도 도착하지 않습니다. 포트 포워딩 규칙은 넣었지만 IP forwarding과 FORWARD 체인을 빠뜨렸습니다.

NAT 장애는 한 줄 규칙 문제가 아니라 패킷이 변환되고 전달되는 전체 경로 문제입니다.

NAT와 포트 포워딩 원리

인터넷 공유기 뒤에 있는 내 PC가 어떻게 유튜브를 볼 수 있을까요? 내부 서버를 외부에서 접속 가능하게 만들려면 무엇을 설정해야 할까요? 이 모든 것의 핵심은 **NAT(Network Address Translation)**입니다. 이 챕터에서는 SNAT과 DNAT의 원리를 이해하고, iptables를 사용하여 실제 포트 포워딩을 구성합니다.


이번 챕터에서 배울 것
  • 1NAT(Network Address Translation)의 필요성과 사설 IP 대역(RFC 1918) 개념을 설명할 수 있다
  • 2SNAT로 내부 사설 IP를 공인 IP로 변환해 외부 인터넷 통신을 허용할 수 있다
  • 3DNAT로 외부 요청의 목적지 IP/포트를 내부 서버로 변환하는 포트 포워딩을 구성할 수 있다
  • 4iptables nat 테이블의 PREROUTING / POSTROUTING 체인 역할과 적용 순서를 이해할 수 있다
  • 5Masquerade와 SNAT의 차이를 알고 동적 IP 환경에 대응할 수 있다
  • 6net.ipv4.ip_forward 커널 파라미터를 설정하고 iptables 규칙을 영구 저장할 수 있다
실습 환경 준비
iptables 설치 및 버전 확인
iptables --version
현재 nat 테이블 규칙 확인
sudo iptables -t nat -L -n -v
IP 포워딩 활성화 여부 확인
sysctl net.ipv4.ip_forward
IP 포워딩 영구 활성화 방법

/etc/sysctl.conf에 net.ipv4.ip_forward=1을 추가한 뒤 sudo sysctl -p 로 적용합니다. 규칙 영구 저장은 iptables-save > /etc/iptables/rules.v4를 사용하세요.

NAT 원리 이해

💡개념

SNAT — 내부에서 외부로 나가는 주소 변환

사무실 내부망 서버(192.168.x.x)에서 인터넷 통신이 됩니다. 그런데 사설 IP는 라우팅이 안 되는 주소입니다. 어떻게 인터넷에 나갔다 돌아오는 걸까요? NAT이 주소를 어떻게 변환하는지 이해하지 못하면 클라우드 VPC에서 NAT Gateway가 왜 필요한지, 포트 포워딩이 어떤 원리로 동작하는지 납득하기 어렵습니다.

SNAT (Source NAT) — 사설 IP로 인터넷에 나가는 원리. 내부 클라이언트(192.168.1.10~12)가 외부 서버(8.8.8.8:80)로 패킷을 보낼 때 NAT 라우터가 출발지 IP를 공인 IP(203.0.113.1)로 변환해 전송하고, NAT 변환 테이블(192.168.1.10:5001→203.0.113.1:40001 등)에 매핑을 기록한다. 외부 서버에는 공인 IP만 보이며(사설 IP는 감춰짐), 응답이 오면 테이블을 참조해 원래 내부 IP:포트로 역변환해 전달한다확대

NAT가 필요한 이유

IPv4 주소 공간(약 43억 개)은 전 세계 기기 수에 비해 턱없이 부족합니다. 이 문제를 해결하기 위해 사설 IP 대역을 내부에서 사용하고, 게이트웨이에서 공인 IP로 변환합니다.

사설 IP 대역 (RFC 1918):

세 가지 대역이 내부 네트워크에서 사용하도록 예약되어 있습니다. 이 주소들은 인터넷에서 라우팅되지 않으므로 중복 사용해도 충돌이 없습니다.

10.0.0.0/8       (10.x.x.x)
172.16.0.0/12    (172.16.x.x ~ 172.31.x.x)
192.168.0.0/16   (192.168.x.x)

SNAT 동작 흐름

SNAT(Source NAT)은 패킷의 출발지 IP 주소를 변환합니다.

SNAT 흐름 — 게이트웨이가 내부 서버 출발지를 공인 IP로 변환하고 응답을 NAT 테이블로 역변환확대

NAT 테이블 (연결 추적):

게이트웨이는 응답 패킷이 돌아왔을 때 어느 내부 호스트로 전달해야 하는지 알기 위해 연결 추적 테이블을 유지합니다. 아래는 두 개의 연결이 동시에 진행될 때 테이블이 어떻게 생겼는지 보여줍니다.

게이트웨이 NAT 추적 테이블:
내부 IP:포트       공인 IP:포트       목적지
10.0.0.10:54321  5.6.7.8:40001   1.2.3.4:80
10.0.0.11:60000  5.6.7.8:40002   8.8.8.8:53

Masquerade — 동적 IP 환경의 SNAT

공인 IP가 고정이면 SNAT에서 --to-source 5.6.7.8처럼 명시합니다. 하지만 DHCP나 PPPoE로 IP가 동적 할당된다면 Masquerade를 사용합니다.

로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part2/exam_10 && cd /tmp/networking/part2/exam_10

# SNAT (고정 공인 IP)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
    -j SNAT --to-source 5.6.7.8

# Masquerade (동적 IP — 가정용 공유기, PPPoE)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o ppp0 \
    -j MASQUERADE
🔍실행 후 확인할 것
  • MASQUERADE 룰 확인iptables -t nat -L POSTROUTING -v 출력에서 MASQUERADE target이 있고 pkts 카운터가 0이 아니면 트래픽이 실제로 NAT를 통과하는 중 — pkts가 계속 0이면 패킷이 해당 체인에 도달하지 않음
  • DNAT 목적지 주소 확인iptables -t nat -L PREROUTING 출력에서 DNAT to: 뒤에 내부 서버 IP:포트가 정확히 기재됐는지 확인 — to:192.168.1.10:80 처럼 IP와 포트가 모두 일치해야 포워딩 동작
  • 포트 LISTEN 여부 교차 확인ss -tlnp로 대상 포트가 LISTEN 상태인지 확인 — DNAT 룰이 있어도 목적지 서버에서 해당 포트가 열려 있지 않으면 연결 거부됨

Masquerade는 ppp0, eth0 등 나가는 인터페이스의 현재 IP를 자동으로 source로 사용합니다.

💡개념

DNAT와 포트 포워딩 — 외부에서 내부로

사설 IP를 가진 내부 서버를 외부에 공개해야 합니다. 공인 IP는 게이트웨이 한 개뿐이고, 포트 8080으로 오는 요청을 내부의 192.168.1.10:80 서버로 보내야 합니다. 이게 포트 포워딩의 전형적인 사례입니다. DNAT가 어떻게 목적지 주소를 바꾸는지 이해해야 iptables 규칙을 직접 작성하거나 설정 오류를 디버깅할 수 있습니다.

DNAT / 포트 포워딩 — 외부에서 내부 서버로 연결. 외부 클라이언트(1.2.3.4)가 공인 IP:포트(203.0.113.1:8080)로 접속하면 NAT 라우터가 목적지 주소를 내부 서버로 변환한다. 포워딩 규칙 예: :8080→192.168.1.10:80(웹 서버), :2222→192.168.1.10:22(SSH), :3306→192.168.1.20:3306(MySQL), :8443→192.168.1.10:443(HTTPS). iptables PREROUTING 체인에 DNAT 규칙(--to-destination)을 넣고 커널의 ip_forward=1이 켜져 있어야 패킷이 내부로 전달된다확대

DNAT 동작 흐름

DNAT(Destination NAT)은 패킷의 목적지 IP/포트를 변환합니다. 포트 포워딩이 대표적인 DNAT 활용 사례입니다.

DNAT 흐름 — 게이트웨이 PREROUTING이 공인 IP:8080을 내부 웹서버로 변환, ip_forward=1이어야 전달확대

iptables 처리 흐름 전체

iptables에는 여러 테이블과 체인이 있습니다. NAT는 nat 테이블에서 처리됩니다.

iptables NAT 체인 흐름 — 패킷 수신→[nat]PREROUTING(DNAT)→라우팅 결정→로컬은 INPUT, 포워딩은 FORWARD→[nat]POSTROUTING(SNAT)→송신확대

DNAT 설정의 핵심 요소

로컬 터미널
iptables -t nat -A PREROUTING \
    -p tcp \           # 프로토콜 (tcp/udp)
    --dport 8080 \     # 외부에서 접속하는 포트
    -j DNAT \          # 액션: Destination NAT
    --to-destination 10.0.0.2:80  # 내부 서버 IP:포트

반드시 필요한 추가 설정: ip_forward가 비활성화되면 NAT 규칙이 있어도 포워딩이 안 됩니다.

위험 명령어

이 명령은 시스템 설정 파일을 변경합니다. 기존 파일 백업과 적용 후 검증 방법을 준비하지 않으면 재부팅이나 서비스 재시작 때 장애가 반복될 수 있습니다.

로컬 터미널
# ip_forward 활성화 (없으면 DNAT 후 패킷이 드랍됨!)
echo 1 > /proc/sys/net/ipv4/ip_forward

# 또는 영구 설정
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

NAT가 주소를 바꾸는 법 — SNAT/DNAT와 conntrack

💡개념

포워딩 패킷이 iptables 체인을 지나는 순서 — DNAT부터 응답 역변환까지

SNAT과 DNAT를 따로 배웠지만, 실제 포트 포워딩 한 건에서는 두 변환과 conntrack이 한 패킷의 여정 위에서 순서대로 맞물립니다. 외부 요청이 게이트웨이에 도착해 내부 서버까지 갔다가 응답이 되돌아오기까지, 각 단계가 iptables의 어느 체인에서 일어나는지를 순서로 보면 "규칙은 맞는데 왜 안 되지"의 대부분이 풀립니다.

TEXT
[외부 클라이언트]  → 공인 5.6.7.8:8080
   │
   ① 패킷 수신 → [nat] PREROUTING  (라우팅 결정 전)
   │    DNAT: 목적지 5.6.7.8:8080 → 10.0.0.2:80 변환
   │    conntrack 에 '원본↔변환' 매핑 기록 (상태 NEW)
   │
   ② 라우팅 결정  (변환된 목적지 10.0.0.2 기준)
   │    내 것 아님 → 포워딩 경로 (net.ipv4.ip_forward=1 필요)
   │
   ③ [filter] FORWARD  (통과 허용 판정)
   │    NEW/ESTABLISHED 허용돼야 통과 (정책 DROP 이면 폐기)
   │
   ④ [nat] POSTROUTING  (송신 직전)
   │    필요시 SNAT/MASQUERADE 로 출발지 변환 (복귀 경로 확보)
   │
   ⑤ 내부 서버 10.0.0.2:80 도착 → 응답 생성
   │
   ⑥ 응답 복귀 → conntrack 이 기존 연결로 인식
   │    자동 역변환: 출발지를 다시 5.6.7.8:8080 으로
   ▼
[외부 클라이언트]  ← 자기가 접속한 그 주소에서 응답 도착

각 단계의 체인 위치와 어긋났을 때 증상:

단계iptables 체인·하는 일여기서 막히면
① 수신·DNATnat/PREROUTING에서 목적지 변환. 라우팅 결정 전이라 '어디로 보낼지' 정하기 전에 목적지를 바꿈. conntrack에 매핑 기록규칙 오타·잘못된 --to-destination이면 엉뚱한 서버로 / pkts=0이면 룰에 트래픽이 안 닿음
② 라우팅·ip_forward변환된 목적지로 포워딩 판단. net.ipv4.ip_forward=1이어야 다른 NIC로 넘어감ip_forward=0이면 DNAT돼도 여기서 폐기 — "룰은 맞는데 안 됨"의 1순위
③ FORWARD 필터filter/FORWARD에서 통과 허용 판정정책 DROP인데 허용 룰 없으면 조용히 드롭
④ 송신·SNATnat/POSTROUTING에서 출발지 변환. 여러 내부 호스트가 공인 IP 하나를 쓰면 출발지 포트를 바꿔 구별(PAT)복귀 경로에 SNAT 없으면 내부 응답이 게이트웨이를 안 거쳐 끊김(헤어핀 NAT)
⑤ 응답 역변환응답을 conntrack이 기존 연결로 인식해 자동 역변환ESTABLISHED,RELATED 응답을 방화벽이 막으면 못 돌아옴

핵심은 conntrack이 연결 단위로 '원본↔변환'을 기억하므로 정방향 규칙만 정의하면 응답은 자동으로 역변환된다는 것입니다. 그래서 역방향 NAT 규칙을 따로 만들 필요가 없습니다. 반대로 이 흐름을 조용히 끊는 두 지점은 늘 정해져 있습니다 — ②의 ip_forward=0과 ③의 FORWARD DROP입니다. 포워딩이 안 되면 sudo iptables -t nat -L -v -npkts 카운터로 트래픽이 각 체인에 닿는지부터 확인하고, ip_forward와 FORWARD 정책을 그다음에 봅니다.

NAT 검증·성능 판단 — 어디서 막히고 무엇이 한계인가
포워딩 룰 넣었는데 접속 안 됨1순위 ip_forward 확인 — sysctl net.ipv4.ip_forward 가 0이면 커널이 전달 안 함. 'DNAT 룰은 맞는데 안 되면 거의 ip_forward'. /etc/sysctl.conf에 영구 1
DNAT는 됐는데 응답이 안 돌아옴복귀 경로 문제 — 내부 서버의 기본 게이트웨이가 NAT 장비가 아니거나 POSTROUTING(SNAT/MASQUERADE) 누락. '가긴 가는데 답이 안 옴=복귀 경로'
룰이 실제 적중하는지 검증iptables -t nat -L -v -n의 pkts 카운터가 증가하는지 확인. 0이면 트래픽이 그 체인에 안 닿음 — 룰 순서·조건 불일치. 'pkts=0이면 룰이 일 안 함'
내부에서 공인IP로 내부서버 접속 안 됨Hairpin NAT(NAT 루프백) 미구성. 외부는 되는데 내부망에서만 안 되는 전형 — 별도 SNAT 룰 필요. '밖은 되고 안에서만 안 됨=헤어핀'
NAT 성능 한계가 걱정병목은 보통 conntrack 테이블·CPU(소프트웨어 NAT). 고대역폭은 nf_conntrack_max 상향 + 멀티큐 NIC, 그래도 한계면 하드웨어 LB/방화벽으로. '동시연결 수가 NAT의 진짜 한계'
포트 포워딩 vs 리버스 프록시단순 L4 전달은 DNAT, HTTP 라우팅·TLS 종료·경로 분기가 필요하면 nginx 등 L7 프록시. 'IP:포트만 바꾸면 NAT, 내용을 보면 프록시'

실습 — iptables NAT 구성

ip_forward 활성화 및 기본 NAT 환경 준비

NAT를 사용하려면 먼저 커널의 IP 포워딩을 활성화해야 합니다.

로컬 터미널
# 현재 ip_forward 상태 확인
cat /proc/sys/net/ipv4/ip_forward
# 0 이면 비활성화 상태

# 즉시 활성화 (재부팅 시 초기화됨)
sudo sysctl -w net.ipv4.ip_forward=1
# 또는
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward

# 영구 활성화 (재부팅 후에도 유지)
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-ip-forward.conf
sudo sysctl --system

# 확인
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1

인터페이스 구성 확인: 어떤 인터페이스가 외부(WAN)/내부(LAN)인지 먼저 확인합니다.

로컬 터미널
# 네트워크 인터페이스 목록
ip addr show

# 예상 환경:
# eth0: 공인(외부) 인터페이스 - 5.6.7.8
# eth1: 사설(내부) 인터페이스 - 10.0.0.1

# 라우팅 테이블
ip route show

현재 iptables 규칙 확인: 기존에 설정된 NAT 규칙을 먼저 파악합니다.

로컬 터미널
# nat 테이블 확인
sudo iptables -t nat -L -n -v

# filter 테이블 확인 (FORWARD 체인)
sudo iptables -L FORWARD -n -v
DNAT 포트 포워딩 설정 — 외부 8080 → 내부 10.0.0.2:80

외부에서 게이트웨이의 8080 포트로 들어오는 트래픽을 내부 웹 서버(10.0.0.2:80)로 전달합니다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 1. DNAT 규칙 추가 (PREROUTING 체인)
sudo iptables -t nat -A PREROUTING \
    -p tcp \
    --dport 8080 \
    -j DNAT \
    --to-destination 10.0.0.2:80

# 2. FORWARD 체인에서 내부 서버로의 트래픽 허용
sudo iptables -A FORWARD \
    -p tcp \
    -d 10.0.0.2 \
    --dport 80 \
    -m state \
    --state NEW,ESTABLISHED,RELATED \
    -j ACCEPT

# 3. 응답 패킷도 허용 (ESTABLISHED 연결)
sudo iptables -A FORWARD \
    -m state \
    --state ESTABLISHED,RELATED \
    -j ACCEPT

# 4. SNAT/Masquerade (내부 서버가 외부로 응답할 때 출발지 변환)
sudo iptables -t nat -A POSTROUTING \
    -s 10.0.0.0/24 \
    -o eth0 \
    -j MASQUERADE

# 규칙 확인
sudo iptables -t nat -L -n -v
sudo iptables -L FORWARD -n -v

테스트: 외부에서 포트 포워딩이 실제로 동작하는지 확인합니다.

로컬 또는 서버
# 외부에서 포트 포워딩 테스트
curl http://5.6.7.8:8080/
# → 10.0.0.2의 웹 서버 응답이 와야 함

# 내부에서 확인 (게이트웨이에서)
curl http://10.0.0.2:80/

여러 포트 포워딩 예시: 서비스별로 다른 포트를 각각 포워딩하는 패턴입니다.

로컬 터미널
# SSH 포워딩: 외부 2222 → 내부 10.0.0.3:22
sudo iptables -t nat -A PREROUTING \
    -p tcp --dport 2222 \
    -j DNAT --to-destination 10.0.0.3:22

# HTTPS 포워딩: 외부 443 → 내부 10.0.0.2:443
sudo iptables -t nat -A PREROUTING \
    -p tcp --dport 443 \
    -j DNAT --to-destination 10.0.0.2:443

# UDP DNS 포워딩: 외부 53 → 내부 DNS 서버 10.0.0.5:53
sudo iptables -t nat -A PREROUTING \
    -p udp --dport 53 \
    -j DNAT --to-destination 10.0.0.5:53
NAT 규칙 영구 저장 및 관리

iptables 규칙은 재부팅 시 사라집니다. 영구 저장 방법을 알아봅니다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 현재 iptables 규칙 저장
sudo iptables-save > /etc/iptables/rules.v4

# 저장된 규칙 확인
cat /etc/iptables/rules.v4

# 규칙 복원
sudo iptables-restore < /etc/iptables/rules.v4

systemd 서비스로 부팅 시 자동 적용 (Ubuntu): iptables 규칙은 재부팅 시 초기화되므로 영구화가 필요합니다.

로컬 터미널
# iptables-persistent 패키지 설치
sudo apt-get install iptables-persistent

# 현재 규칙을 영구 저장
sudo netfilter-persistent save

# 서비스 상태 확인
sudo systemctl status netfilter-persistent

RHEL/CentOS (firewalld 대신 iptables 직접 사용 시): iptables-save로 규칙을 저장하고 재부팅 시 복원합니다.

로컬 터미널
# iptables 서비스 설치
sudo yum install iptables-services

# 규칙 저장
sudo service iptables save
# /etc/sysconfig/iptables 에 저장됨

# 부팅 시 자동 시작
sudo systemctl enable iptables

규칙 삭제 방법: 잘못 설정한 규칙은 -D 옵션으로 특정 규칙만 삭제합니다.

로컬 터미널
# 특정 규칙 삭제 (-D: delete)
sudo iptables -t nat -D PREROUTING \
    -p tcp --dport 8080 \
    -j DNAT --to-destination 10.0.0.2:80

# 모든 nat 테이블 규칙 초기화
sudo iptables -t nat -F

# 규칙 번호로 삭제
sudo iptables -t nat -L PREROUTING --line-numbers
sudo iptables -t nat -D PREROUTING 2  # 2번 규칙 삭제

트러블슈팅

증상

iptables DNAT 규칙을 추가했는데 외부에서 접속이 되지 않습니다.

로컬 터미널
# 게이트웨이에서 규칙 확인
sudo iptables -t nat -L PREROUTING -n -v
# Chain PREROUTING (policy ACCEPT)
# target     prot opt source    destination
# DNAT       tcp  --  0.0.0.0/0 0.0.0.0/0   tcp dpt:8080 to:10.0.0.2:80

# 규칙은 있는데 외부에서 curl 하면?
curl http://5.6.7.8:8080/
# curl: (7) Failed to connect to 5.6.7.8 port 8080: Connection refused

진단

로컬 터미널
# ip_forward 상태 확인
cat /proc/sys/net/ipv4/ip_forward
# 0  ← 비활성화 상태!

# 패킷이 드랍되는지 확인
sudo iptables -L FORWARD -n -v
# Chain FORWARD (policy DROP)  ← DROP 정책!
# → ip_forward=0이거나 FORWARD 체인이 DROP 정책이면 포워딩 안 됨

패킷 흐름 추적: iptables LOG 타겟으로 NAT 규칙을 통과하는 패킷을 기록합니다.

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# iptables 로그 규칙 추가 (진단용)
sudo iptables -t nat -I PREROUTING 1 \
    -p tcp --dport 8080 \
    -j LOG --log-prefix "NAT-PRE: "

sudo iptables -I FORWARD 1 \
    -p tcp \
    -j LOG --log-prefix "FWD: "

# 로그 확인
sudo journalctl -f | grep -E "NAT-PRE|FWD"
# 외부에서 접속 시도 후 로그 확인

해결

위험 명령어

이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.

로컬 터미널
# 1. ip_forward 활성화
sudo sysctl -w net.ipv4.ip_forward=1

# 2. FORWARD 체인 정책 또는 규칙 확인
sudo iptables -L FORWARD -n -v

# FORWARD 정책이 DROP이라면 내부 서버로 향하는 트래픽 명시적 허용
sudo iptables -A FORWARD \
    -d 10.0.0.2 \
    -p tcp \
    --dport 80 \
    -j ACCEPT

# 3. 영구 설정
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-forward.conf
sudo sysctl --system

체크리스트

□ net.ipv4.ip_forward = 1 확인
□ iptables FORWARD 체인 정책 및 규칙 확인
□ iptables PREROUTING DNAT 규칙 존재 확인
□ 내부 서버 방화벽에서 해당 포트 허용 확인
□ 내부 서버 서비스가 실제로 실행 중인지 확인

증상

외부에서는 curl http://5.6.7.8:8080/이 정상 동작하는데, 같은 내부망의 다른 서버에서 공인 IP로 접속하면 실패합니다.

로컬 또는 서버
# 내부 서버 (10.0.0.10)에서 실행
curl http://5.6.7.8:8080/
# 연결 안 됨 또는 타임아웃

원인

이것은 Hairpin NAT 문제입니다. 내부에서 공인 IP로 나가는 패킷이 게이트웨이에서 DNAT되어 10.0.0.2로 향하지만, 응답 패킷이 게이트웨이를 거치지 않고 직접 10.0.0.10으로 가려 해서 연결이 끊깁니다.

Hairpin NAT 문제 — 내부에서 공인 IP로 접속 시 응답이 게이트웨이를 거치지 않고 직접 와 출발지 불일치로 연결이 끊김확대

해결 — SNAT 추가 (Hairpin NAT)

로컬 터미널
# 내부에서 공인 IP로 접속 시 출발지도 게이트웨이 IP로 변환
sudo iptables -t nat -A POSTROUTING \
    -s 10.0.0.0/24 \
    -d 10.0.0.2 \
    -p tcp \
    --dport 80 \
    -j MASQUERADE

# 이렇게 하면:
# 10.0.0.10 → 5.6.7.8:8080
# DNAT: dst 5.6.7.8:8080 → 10.0.0.2:80
# SNAT: src 10.0.0.10 → 10.0.0.1 (게이트웨이)
# 10.0.0.2 응답: dst 10.0.0.1 → 게이트웨이
# 게이트웨이가 역변환: 10.0.0.10에게 전달

심화 — 공인 IP 하나로 낼 수 있는 연결에는 상한이 있다

💡개념

심화: SNAT 출발지 포트 고갈 — 대규모 아웃바운드의 숨은 벽

NAT는 평소엔 투명하지만, 대규모 아웃바운드에서 갑자기 '간헐적 연결 실패'로 발목을 잡습니다. 원인은 하나의 공인 IP 뒤에서 동시에 유지할 수 있는 연결 수에 물리적 상한이 있기 때문입니다. conntrack이 연결을 어떻게 구별하는지 알면 이 벽이 왜 생기는지 보입니다.

  • 연결은 5-튜플로 구별된다: 프로토콜·출발지 IP·출발지 포트·목적지 IP·목적지 포트. SNAT/MASQUERADE는 출발지 IP를 공인 IP 하나로 통일하면서 겹치지 않게 출발지 포트를 골라 줍니다.
  • 같은 목적지로 몰리면 포트가 바닥난다: 목적지 IP·포트가 동일한(예: 외부 API 한 곳) 연결이 수만 개면, 구별에 남는 자유도는 출발지 포트(대략 28k~64k개)뿐입니다. 이게 소진되면 conntrack이 새 연결에 유니크한 매핑을 못 만듭니다.
  • 증상이 '간헐적'이라 헷갈린다: 전체가 죽지 않고 일부 새 연결만 SYN 재전송·타임아웃·리셋. conntrack -Sinsert_failed가 증가하고 dmesg에 경고가 뜹니다.
  • 테이블 크기 문제와는 다르다: conntrack 테이블이 가득 차는 것(nf_conntrack table full)과 특정 목적지에 대한 포트 고갈은 별개입니다 — 후자는 테이블에 여유가 있어도 발생합니다.

해결 방향은 SNAT용 공인 IP를 여러 개로 늘려 포트 풀을 배수로 확장하거나, 애플리케이션 keep-alive·커넥션 풀로 동시 연결 수를 줄이거나, 목적지를 분산하고 conntrack 타임아웃을 낮춰 매핑을 빨리 회수하는 것입니다.

상황

배치·크롤러·푸시 발송처럼 하나의 외부 엔드포인트로 대량 연결을 여는 시간대에만, 요청 일부가 연결 실패(SYN 재전송 후 타임아웃)합니다. CPU·메모리·회선 대역폭은 모두 여유가 있어 자원 지표만 보면 원인이 안 보입니다.

원인

내부 다수 호스트가 MASQUERADE로 공인 IP 하나를 공유하는데, 목적지가 같은 API 한 곳이라 연결 구별에 출발지 포트만 쓸 수 있습니다. 동시 연결이 가용 포트 수를 넘자 conntrack이 새 연결에 겹치지 않는 매핑을 만들지 못해, 삽입 실패로 첫 SYN 단계에서 패킷이 버려졌습니다.

진단

로컬 터미널
# insert_failed 카운터가 증가하는지
conntrack -S | tr ' ' '\n' | grep insert_failed

# 특정 목적지로 몰린 연결 수 세기
conntrack -L -d 203.0.113.50 2>/dev/null | wc -l

# 커널 경고 확인
sudo journalctl -k | grep -Ei 'nf_conntrack|table full'

같은 목적지 IP:포트로 향하는 연결이 수만 개인데 insert_failed가 함께 오르면 포트 고갈로 확정합니다.

해결

SNAT용 공인 IP를 여러 개로 늘려(--to-source A.B.C.D-A.B.C.G 범위) 출발지 포트 풀을 배수로 확장합니다. 애플리케이션에서 HTTP keep-alive·커넥션 풀로 동시 연결 수 자체를 줄이고, 가능하면 목적지를 여러 엔드포인트로 분산합니다. 단기 처방으로 TIME_WAIT·conntrack 타임아웃을 낮춰 매핑을 빨리 회수할 수 있습니다.


실무 맥락

💼
실무 맥락
현업 패턴

AWS에서의 NAT

AWS에서는 대부분의 NAT를 관리형 서비스로 처리합니다.

AWS NAT 구성 옵션:
1. NAT Gateway (관리형)
   - 고가용성, 자동 스케일
   - 시간당 비용 발생
   - 권장: 프로덕션 환경

2. NAT Instance (EC2)
   - iptables Masquerade 직접 설정
   - 비용 절감, 커스터마이징 가능
   - 단일 장애점 주의

# NAT Instance 설정 (EC2 Amazon Linux)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

iptables -t nat -A POSTROUTING \
    -s 10.0.0.0/16 \
    -o eth0 \
    -j MASQUERADE

쿠버네티스에서의 NAT

쿠버네티스 kube-proxy는 서비스 ClusterIP를 실제 Pod IP로 DNAT합니다.

로컬 터미널
# 쿠버네티스 서비스 포트포워딩과 NAT 확인
sudo iptables -t nat -L -n | grep KUBE

# 예시 출력:
# KUBE-SERVICES  all  -- 0.0.0.0/0  0.0.0.0/0  /* kubernetes service rules */
# DNAT           tcp  -- 0.0.0.0/0  10.96.0.1   tcp dpt:443 to:192.168.1.10:6443

포트 포워딩 보안 고려사항

포트 포워딩 설정 시 보안 체크리스트:
□ 필요한 포트만 최소한으로 열기
□ 소스 IP 제한 추가 (-s 203.0.113.0/24)
□ 불필요한 포트는 정기적으로 닫기
□ fail2ban 등 브루트포스 차단 도구 적용
□ 포트 포워딩 목록을 문서화하여 팀 공유
□ VPN으로 대체 가능한지 검토 (더 안전)

실무에서 자주 보는 NAT 시나리오

로컬 터미널
# 1. 사무실 → 인터넷 (Masquerade)
iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -o wan0 -j MASQUERADE

# 2. 외부 → 내부 웹 서버
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 10.0.0.10:80
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to 10.0.0.10:443

# 3. 외부 → 내부 SSH (비표준 포트로 노이즈 줄이기)
iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to 10.0.0.5:22

# 4. 소스 IP 제한 포트포워딩 (관리 포트)
iptables -t nat -A PREROUTING \
    -s 203.0.113.0/24 \  # 허용된 관리 IP 대역만
    -p tcp --dport 8443 \
    -j DNAT --to 10.0.0.100:443

정리

NAT 유형

  • SNAT (Source NAT) — 내부→외부, 사설 IP→공인 IP, POSTROUTING 체인에서 처리 (Masquerade는 동적 IP 환경용 SNAT)
  • DNAT (Destination NAT) — 외부→내부(포트 포워딩), 공인 IP:포트→사설 IP:포트, PREROUTING 체인에서 처리

iptables NAT 핵심 명령어

  • DNAT: iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.2:80
  • Masquerade: iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
  • ip_forward: sysctl -w net.ipv4.ip_forward=1 (필수!)

주요 트러블슈팅

  • 포워딩 안 됨 → ip_forward=0 확인
  • FORWARD 체인 DROP 정책 → 허용 규칙 추가
  • Hairpin NAT → 내부망에서 공인 IP 접속 시 SNAT 추가 필요

명령어·단축키 빠른 참조

이 모듈에서 다룬 iptables NAT·포트 포워딩 명령을 실전 옵션과 함께 모았습니다.

명령어용도자주 쓰는 예
sysctl net.ipv4.ip_forwardIP 포워딩 활성 여부 확인/설정sudo sysctl -w net.ipv4.ip_forward=1 (0이면 DNAT해도 드랍)
iptables -t nat -A PREROUTING … -j DNAT포트 포워딩(목적지 변환)--dport 8080 -j DNAT --to-destination 10.0.0.2:80
iptables -t nat -A POSTROUTING … -j MASQUERADE동적 IP SNAT(내부→외부)-s 10.0.0.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING … -j SNAT고정 공인 IP SNAT-j SNAT --to-source 5.6.7.8
iptables -A FORWARD … -j ACCEPT포워딩 트래픽 허용(정책 DROP 대비)-d 10.0.0.2 --dport 80 -m state --state NEW,ESTABLISHED,RELATED
iptables -t nat -L -n -vNAT 룰·적중(pkts) 확인pkts=0이면 트래픽이 그 체인에 안 닿음
iptables -t nat -D / -F룰 삭제/초기화-D PREROUTING 2(번호 삭제), -F(nat 전체 초기화)
iptables -t nat -I PREROUTING 1 … -j LOG패킷 흐름 추적--log-prefix "NAT-PRE: "journalctl -f | grep NAT-PRE
iptables-save / -restore규칙 영구 저장·복원iptables-save > /etc/iptables/rules.v4
ss -tlnp대상 포트 LISTEN 교차 확인DNAT 대상 서버에서 해당 포트가 열렸는지
conntrack -S / -L -d <IP>SNAT 포트 고갈 진단conntrack -S | grep insert_failed, conntrack -L -d 203.0.113.50 | wc -l

관련 모듈로 더 깊이:

다음 챕터에서는 VPN과 제로 트러스트 보안 아키텍처를 학습하여, 원격 접속 환경을 안전하게 구축하는 방법을 배웁니다.

지식 확인

퀴즈 — 8문제

Q1

SNAT(Source NAT)는 주로 어떤 목적으로 사용됩니까?

Q2

iptables로 외부 8080 포트를 내부 서버 10.0.0.2:80으로 포워딩하는 올바른 명령어는?

Q3

포트 포워딩 iptables 규칙을 추가했는데 외부에서 접속이 안 됩니다. 가장 먼저 확인해야 할 리눅스 커널 설정은?

Q4

Masquerade와 SNAT의 차이점은 무엇입니까?

Q5

iptables NAT 규칙에서 POSTROUTING 체인과 PREROUTING 체인의 차이는?

Q6

외부 8080 → 내부 10.0.0.2:80으로 DNAT 포트포워딩을 걸었더니, 응답 패킷을 위한 역방향 규칙을 따로 안 만들었는데도 통신이 양방향으로 잘 된다. 그 이유는?

Q7

[심화] 내부 호스트 수천 대가 MASQUERADE로 공인 IP 하나를 공유해 같은 외부 API로 대량 연결을 연다. 동시 연결 수에 물리적 상한이 생기는 이유는?

Q8

[심화] 대량 아웃바운드가 몰리는 시간대에만 일부 연결이 SYN 타임아웃으로 실패하고 회선·서버 자원은 멀쩡하다. 원인을 확정하려면 무엇을 봐야 하는가?

0 / 8 답변

🧪 실습으로 확인하기

NAT·포트포워딩 — 내부 서버 외부 노출 디버깅

고급

사설 IP 내부 서버를 외부에 노출하는 DNAT(포트포워딩)이 안 될 때, NAT 동작(SNAT/DNAT)을 이해하고, iptables nat 규칙·IP 포워딩 커널 설정·방화벽·복귀 경로(비대칭)를 순서대로 점검해 끊긴 고리를 찾는다. conntrack으로 변환을 추적하는 법도 다룬다.

45📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요