Post

[Network] 포트포워딩(Port Forwarding) 개념 정리

포트포워딩(Port Forwarding)이 무엇인지와 종류에 대해서 알아본다.

[Network] 포트포워딩(Port Forwarding) 개념 정리

🔍 포트포워딩(Port Forwarding)이란?

특정 포트로 들어온 트래픽을 다른 주소·포트로 전달하는 기술

가장 흔하게 사용되는 기술은 SSH 터널링인데, 어느 계층/장비에서 처리하느냐에 따라 여러 방식이 있다.

종류 처리 주체 주로 쓰이는 상황
공유기(NAT) 포트포워딩 홈/사무실 공유기 외부에서 내부망 기기(홈서버, 게임 서버 등)로 접속 허용
iptables/nftables 포트포워딩 리눅스 방화벽(커널) 서버 자체에서 특정 포트 트래픽을 다른 포트·호스트로 리다이렉트
Docker 포트포워딩 Docker 엔진 컨테이너 내부 포트를 호스트 포트에 매핑 (-p 8080:80)
클라우드 LB / 보안그룹 ALB, NLB 등 리스너 포트를 인스턴스의 다른 포트로 전달
SSH 포트포워딩 SSH 클라이언트/서버 별도 설정 없이 SSH 터널로 임시 접근 경로 확보


🏠 공유기(NAT) 포트포워딩

image

집에서 사용하는 공유기는 내부망(컴퓨터, 스마트폰, 프린터, IoT 기기 등)의 사설 IP와 인터넷의 공인 IP가 통신 가능하도록 NAT(Network Address Translation)를 수행한다.

기본적으로 외부에서 들어오는 요청(DNAT 대상)은 내부망의 어떤 기기로 가야할 지 알 수가 없어서 차단된다. 내부에서 나가는 요청(SNAT 대상)은 포트포워딩 없이도 가능하다. 물론 내부에서 나가는 요청에 대한 응답도 받을 수 있다.

그럼 외부에서 들어오는 요청을 받기 위해서는 어떻게 해야할까?

이럴 때 바로 포트포워딩 규칙을 사용한다.

포트포워딩 규칙을 등록해두면 공인 IP의 특정 포트로 들어온 요청이 내부 IP:포트로 보내라는 매핑이 만들어지고 NAT 테이블에 규칙으로 저장된다.

[참고] 불필요한 포트를 열어두면 외부 공격에 그대로 노출된다. 꼭 필요한 포트만 열고, 가능하면 IP 제한이나 VPN을 함께 쓰는 게 안전하다고 한다.


🧱 iptables/nftables 포트포워딩

리눅스 커널의 “netfilter”가 처리하는 방식으로, 서버 자체가 라우터처럼 동작한다.

위에서 말했던 공유기 포트포워딩과 비교를 해보자면, 안내하는 주체가 공유기에서 리눅스 서버 자체(커널)로 바뀐다는 것이다. 안내를 하는 위치도 다른데, 공유기 포트포워딩의 경우 비유를 하자면 집 문 앞에서 집 안의 방을 안내하는 것이고, iptables 포트포워딩은 방 안에서 다른 방으로 한 번 더 안내한다고 보면 된다.

iptablesnat 테이블 중 PREROUTING 체인(검문소 역할)에 DNAT(Destination NAT) 규칙을 추가하면, 패킷이 라우팅 결정을 내리기 전에 목적지 주소·포트를 바꿔버린다.

즉 패킷이 서버에 도착하는 순간, 커널 레벨에서 목적지를 바꿔치기 하는 것이다.

순서를 보면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
1. 패킷 도착 (원래 목적지: 서버IP:80)
        ↓
2. PREROUTING 검문소 통과
   → 여기서 DNAT 규칙 발견: "80으로 오는 건 8080으로 바꿔"
   → 목적지가 8080으로 슬쩍 바뀜
        ↓
3. 라우팅 결정 ("어디로 보낼까?")
   → 이미 바뀐 8080을 기준으로 길을 정함
        ↓
4. 실제로 8080번 프로세스에 전달됨

nftablesiptables의 차세대 버전이다. 하지만 아직도 iptables를 많이 사용하는 듯.


80과 8080으로 예시를 드니까 개발한 서비스 배포할 때가 생각날 것이다. 근데 보통은 iptables를 직접 사용해 본 적은 많이 없을 것이다. 왜냐하면 nginx가 이미 그 역할을 대신 해주고 있기 때문이다.

❓ 그럼 nginx가 iptables를 대체한 것일까?

사실 nginx와 iptables는 비슷해 보여도 동작하는 계층(레이어) 자체가 다르다.

iptables는 L3/L4(네트워크/전송 계층)에서 동작해서, IP와 포트만 보고 목적지를 바꿔친다. 즉 “80번으로 오면 8080번으로”처럼 단순하게 포트 단위로만 판단할 수 있고, 요청 안에 뭐가 들어있는지는 전혀 모른다.

반면 nginx는 L7(애플리케이션 계층)에서 동작한다. 실제로 HTTP 요청을 받아서 내용을 이해하기 때문에, URL 경로나 도메인에 따라 다른 서버로 분기시킬 수 있다. 이건 iptables가 절대 할 수 없는 일인데, iptables 입장에서는 그냥 포트로 들어온 패킷일 뿐 그 안에 어떤 경로로 요청이 왔는지는 알 방법이 없기 때문이다.

그 외에도 겹치지 않는 역할들이 많아서 nginx가 iptables를 대체한 것은 아니고 실무에서도 둘을 같이 사용한다고 한다.

❓ 그럼 여기서 또 다른 의문이 생긴다. “그럼 LB랑 비슷한 역할인 거 아니야? 특히 NLB. NLB도 port 단위에서 트래픽을 받아서 다른 목적지로 전달해주는 거잖아.” NLB는 nginx와 다르게 L4에서 동작하니, iptables와 레이어가 똑같은 셈이다.

하지만 이 둘도 분명 차이가 존재한다. NLB와 iptables는 같은 L4인데 동작하는 위치가 다르다.

NLB는 “여러 인스턴스 중 어디로 보낼지”를 정하는 분산 문제를 처리하고, iptables는 “그 인스턴스 안에서 포트를 어떻게 처리할지”를 다루는 로컬 문제다. 그래서 NLB를 쓴다고 해서 인스턴스 내부의 iptables가 사라지거나 필요 없어지는 게 아니다.

실제로 인스턴스 안에서는 이런 일들이 여전히 일어나고 있다.

  • Docker: NLB가 트래픽을 EC2의 8080 포트로 보내줘도, 그 안에서 컨테이너로 앱이 떠 있으면 Docker가 내부적으로 iptables 규칙을 자동 생성해서 컨테이너 내부 IP로 다시 한번 전달한다.
  • 인스턴스 내부 방화벽: AWS에서는 보통 iptables 대신 보안그룹(Security Group)으로 포트 접근을 제어하지만, 더 세밀한 제어가 필요하면 인스턴스 안에서 iptables를 추가로 쓰기도 한다.

즉 nginx가 iptables와 역할이 완전히 다른 계층이라 같이 쓰이는 관계였다면, NLB와 iptables는 같은 레이어의 원리를 다른 위치(클라우드 바깥 vs 인스턴스 내부)에서 각자 담당하는 관계에 가깝다.

결론적으로 NLB는 iptables를 “대체”한다기보다, iptables가 하는 일의 앞단에 분산 역할이 하나 더 추가된 것이라고 보면 된다.


그리고 iptables가 사용되는 경우가 또 있다.

리눅스에서 80번, 443번 같은 낮은 번호 포트는 관리자(root) 권한이 있어야만 프로그램이 직접 쓸 수 있는데, 그렇다고 매번 root로 앱을 실행하는 건 위험하다.

그래서 내 앱은 일반 권한으로 8080번에서 실행하되, iptables한테 80으로 오는 트래픽은 8080으로 보내달라고 규칙을 등록한다.

1
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

이러면 사용자는 그냥 http://내서버(80번)로 접속하는데, 실제로는 내부에서 조용히 8080번으로 전달된다.

PREROUTING은 들어오는 패킷의 목적지를 바꿀 때, OUTPUT은 로컬에서 나가는 패킷의 목적지를 바꿀 때 사용


🐳 Docker 포트포워딩

Docker 컨테이너는 기본적으로 격리된 자체 네트워크 네임스페이스와 내부 IP(보통 docker0 브리지 대역)를 가진다.

호스트(또는 외부)에서 접속해야 하는 컨테이너를 생성할 때 docker run-p 옵션으로 포트를 매핑하는데, 이 옵션을 사용하게 되면 Docker 데몬이 내부적으로 iptables DNAT 규칙을 자동으로 생성해서 호스트의 특정 포트로 들어온 트래픽을 컨테이너 내부 IP:포트로 전달한다.

1
2
# 호스트의 8080번 포트를 컨테이너의 80번 포트에 매핑
docker run -d -p 8080:80 nginx

같은 이미지의 컨테이너를 여러 개 띄울 때도 이 방식을 응용할 수 있는데, 호스트 포트를 8081, 8082처럼 다르게 매핑해주면 포트 충돌 없이 각 컨테이너에 접근할 수 있다.

또한 운영 서버를 배포할 때도 컨테이너 내부 포트는 80으로 고정하고, 호스트 포트만 바꿔가면서 블루/그린 배포 등에 활용할 수 있다.


☁️ 클라우드 로드밸런서 포트포워딩

AWS ALB(Application Load Balancer)나 NLB(Network Load Balancer) 같은 로드밸런서는 리스너(Listener)가 특정 포트(예: 443)로 요청을 받아, 타겟 그룹(Target Group)에 등록된 인스턴스의 다른 포트(예: 8080)로 트래픽을 전달한다. 이 과정에서 SSL 종료(SSL termination), 헬스체크, 여러 인스턴스로의 분산까지 함께 처리된다.

실제 흐름에선 방화벽 역할을 하는 보안그룹(Security group)과 함께 사용되어,

사용자 → [보안그룹: 허용 여부] → LB(포트 변환) → [보안그룹: 허용 여부] → 인스턴스 처럼 트래픽이 흐른다.


🔧 SSH 포트포워딩

SSH 포트포워딩은 SSH 클라이언트와 서버 사이에 이미 맺어진 암호화된 연결(SSH 세션) 위에, 다른 트래픽을 함께 실어 보내는 방식이다.

이렇게 SSH 연결 하나로 감싸서 데이터를 주고 받는 것을 SSH 터널링이라고 한다.

원래 SSH는 서버에 로그인해서 명령어를 실행하기 위한 프로토콜이지만, 그 연결 통로(터널) 자체를 다른 목적(웹 트래픽, DB 접속 등)으로도 재사용할 수 있다.

image

클라이언트가 자신의 로컬 포트로 보낸 데이터는 SSH 터널을 타고 암호화된 채로 서버까지 전달되고, 서버 쪽에서 원래 목적지로 다시 풀어서 전달한다.

예를 들어, ssh -L 8080:localhost:80 user@ssh-server로 SSH 터널을 만들어서 연결하는 경우, 아래와 같은 흐름으로 트래픽이 흐른다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[내 PC]                                    [SSH 서버]
localhost:8080                              (127.0.0.1:80에 nginx 등이 떠 있음)
    │                                             │
    │ 1. 브라우저 → SSH 클라이언트                 │
    │    원본 HTTP 요청 (평문)                     │
    │    "GET / HTTP/1.1\r\nHost: localhost:8080" │
    │                                             │
    │ 2. SSH 채널 계층으로 1차 캡슐화              │
    │    [channel_id=3, payload=원본 HTTP 바이트]  │
    │                                             │
    │ 3. SSH 전송 계층에서 암호화 (2차 캡슐화)      │
    │    → 완전히 랜덤해 보이는 암호문              │
    ├───────────────────────────────────────────>│
    │         (22번 포트 통해 이동)               │
    │                                            │ 4. SSH 서버가 암호문 복호화
    │                                            │    → SSH 채널 데이터 추출
    │                                            │    → 원본 HTTP 바이트 복원
    │                                            │
    │                                            │ 5. "8080 채널 데이터 → localhost:80"
    │                                            │    규칙에 따라 127.0.0.1:80으로
    │                                            │    새 TCP 연결 열어 그대로 전달
    │                                            ▼
    │                                       [nginx:80]
    │                                            │
    │                                            │ 6. nginx가 평범한 HTTP 요청으로 처리
    │                                            │    (SSH를 거쳤다는 걸 전혀 모름)
    │                                            │    응답 생성
    │                                            │
    │                                            │ 7. 응답도 2~3 과정 그대로 역으로
    │                                            │    (채널 데이터 포장 → 암호화)
    │<───────────────────────────────────────────┤
    │                                            │
    │ 8. SSH 클라이언트가 복호화 + 채널 데이터 추출 │
    ▼                                            │
브라우저가 원본 응답 수신

이처럼 SSH 포트포워딩을 사용하면 별도의 인프라 구축 없이 이미 열려있는 SSH 접속으로 암호화된 임시 접근 경로를 만들 수 있다.

SSH 포트포워딩은 용도에 따라 크게 3가지로 구분된다.

1️⃣ 로컬 포트포워딩 (Local Port Forwarding)

로컬 포트포워딩은 ssh -L로 연결하며, 방화벽 등 직접 접근이 불가능한 내부 서버에 접근할 때 사용한다.

1
ssh -L 8080:target-server:80 user@ssh-server

image

내 PC:8080 → SSH 서버(ssh-server) 경유 → target-server:80

2️⃣ 원격 포트포워딩 (Remote Port Forwarding)

원격 포트포워딩은 ssh -R로 연결하며, 내부망에 있는 내 PC를 외부에서 접근할 때 사용한다. (로컬 포워딩과 반대 방향)

로컬에서 개발 중인 서버를 외부 팀원이나 웹훅(webhook) 테스트용으로 잠깐 공개할 때 등 사용할 수 있다.

원격 포트포워딩은 SSH 서버 쪽에 내 로컬 서비스를 노출시키는 것이므로, 보안 설정(GatewayPorts 등)을 확인하지 않으면 의도치 않게 외부에 열릴 수 있다.

1
ssh -R 8080:localhost:3000 user@ssh-server

image

외부 사용자 → SSH 서버(ssh-server:8080) 경유 → 내 PC(localhost:3000)

3️⃣ 다이나믹 포트포워딩 (Dynamic Port Forwarding)

다이나믹 포트포워딩은 ssh -D로 연결하며, 로컬/원격 포워딩처럼 목적지를 고정하지 않고, SSH 서버를 SOCKS 프록시로 사용한다.

SOCKS(SOCket Secure) 프록시는 클라이언트가 어떤 IP:포트로 연결해달라고 요청하면 그 연결을 대신 맺어주고 데이터를 그대로 중계하는 역할을 한다.

여러 목적지 트래픽을 상황에 따라 자유롭게 SSH 서버 경유로 우회시킬 때 사용한다. 공용 와이파이에서 안전하게 인터넷을 쓰고 싶을 때 사용할 수도 있다.

1
ssh -D 1080 user@ssh-server

image

내 PC(localhost:1080, SOCKS) → SSH 서버(ssh-server) 경유 → 목적지(사이트 A/B/C)


✅ 요약

  • 포트포워딩: 특정 포트로 들어온 트래픽을 다른 주소·포트로 전달하는 기술
종류 언제 쓰나 (용도) 어떻게 (동작)
공유기(NAT) 포트포워딩 집/사무실 밖에서 홈서버·게임서버 등 내부망 기기에 처음 접속해야 할 때 공인 IP:포트 → 사설 IP:포트로 정적 매핑
iptables/nftables 포트포워딩 서버 자체에서 낮은 포트(80/443) 권한 문제를 우회하거나, 별도 프록시 없이 가볍게 포트만 바꾸고 싶을 때 PREROUTING에서 DNAT로 목적지를 라우팅 전에 미리 변경
Docker 포트포워딩 컨테이너를 호스트나 외부에 노출해야 할 때, 여러 컨테이너를 포트 충돌 없이 운영할 때 -p 옵션 시 iptables DNAT 규칙 자동 생성
클라우드 로드밸런서(LB) 여러 인스턴스로 트래픽을 분산하고, SSL 종료·헬스체크까지 인프라 레벨에서 관리하고 싶을 때 리스너 포트 → 타겟 그룹 포트로 변환 + 분산
SSH 포트포워딩 별도 인프라 구축 없이 임시로 암호화된 접근 경로가 필요할 때 (내부망 접근, 로컬 서비스 노출, 프록시 우회) 이미 열린 SSH 세션 위에 다른 트래픽을 캡슐화해서 전달
This post is licensed under CC BY 4.0 by the author.