SSH 포트 포워딩과 터널링

Local/Remote/Dynamic 포트 포워딩, Bastion Host, SSH 터널 활용

SSH 포트 포워딩의 세 가지 유형을 다룬다. 로컬 포트 포워딩으로 원격 DB 접속, 리모트 포트 포워딩으로 로컬 서버 공개, 다이나믹 포트 포워딩(SOCKS 프록시), Bastion Host 아키텍처까지 정리한다.

Engineering
Infrastructure
Security
저자

Kwangmin Kim

공개

2025년 11월 27일

1 포트 포워딩이란

SSH 포트 포워딩은 암호화된 SSH 터널을 통해 네트워크 트래픽을 전달하는 기법이다. 방화벽으로 막힌 서비스에 접근하거나, 보안이 필요한 통신을 암호화할 때 사용한다.

세 가지 유형이 있다:

유형 방향 주요 용도
로컬 포트 포워딩 로컬 → 원격 원격 DB, 웹 서비스를 로컬에서 접근
리모트 포트 포워딩 원격 → 로컬 로컬 개발 서버를 외부에 공개
다이나믹 포트 포워딩 SOCKS 프록시 전체 트래픽 프록시

2 로컬 포트 포워딩 (Local Forward)

로컬 PC의 포트를 원격 서버의 포트로 연결한다. 가장 많이 사용하는 유형이다.

ssh -L [로컬포트]:[목적지호스트]:[목적지포트] user@server

2.1 원격 데이터베이스 접속

원격 서버의 MySQL(3306)에 로컬에서 접근:

ssh -L 3306:localhost:3306 admin@db.company.com
  • 로컬의 localhost:3306으로 접속하면 원격 서버의 MySQL에 연결된다
  • MySQL Workbench, DBeaver 등에서 localhost:3306으로 접속하면 된다
# 터널 열린 상태에서 별도 터미널에서:
mysql -h localhost -P 3306 -u dbuser -p

2.2 Jupyter Notebook 원격 접속

GPU 서버에서 Jupyter를 실행하고, 로컬 PC 브라우저에서 접속하는 워크플로이다.

# [1] 서버에서 Jupyter 실행 (브라우저 없이)
poetry run jupyter notebook --no-browser --port 8888
# 출력에서 토큰 확인: http://localhost:8888/tree?token=abc123...

# [2] 로컬 PC에서 새 터미널을 열고 SSH 터널 생성
ssh -L 8888:localhost:8888 user@ml-server

# [3] 로컬 브라우저에서 접속
# http://localhost:8888 → 로그인 화면에 토큰 붙여넣기
[로컬 PC]                          [GPU 서버]
브라우저                            Jupyter (포트 8888)
   |                                     ^
   |  http://localhost:8888              |
   v                                     |
로컬 포트 8888 <---- SSH 터널 ----> 서버 포트 8888

매번 토큰을 복사하기 번거로우면 서버에서 jupyter notebook password로 비밀번호를 설정한다. 8888 포트가 이미 사용 중이면 서버와 터널 양쪽 모두 다른 포트 번호(예: 9999)로 변경하면 된다.

2.3 원격 웹 서버 접속 (방화벽 우회)

ssh -L 8080:localhost:80 user@web-server
# 브라우저: http://localhost:8080

2.4 백그라운드 실행

포트 포워딩만 유지하고 셸은 사용하지 않는 경우:

ssh -f -N -L 3306:localhost:3306 user@db-server
옵션 설명
-f 백그라운드 실행
-N 명령 실행 안 함 (포워딩만)

3 리모트 포트 포워딩 (Remote Forward)

원격 서버의 포트를 로컬 PC로 연결한다. 로컬 개발 서버를 외부에서 접근 가능하게 만들 때 사용한다.

ssh -R [원격포트]:[목적지호스트]:[목적지포트] user@server

3.1 로컬 웹서버 외부 공개

ssh -R 8080:localhost:3000 user@public-server
  • public-server:8080으로 접속하면 로컬 PC의 localhost:3000에 연결된다
  • 데모, 테스트 시 로컬 개발 서버를 팀원에게 공유할 때 유용하다
노트

리모트 포트 포워딩을 사용하려면 서버의 /etc/ssh/sshd_configGatewayPorts yes가 설정되어 있어야 외부에서 접근 가능하다.

4 다이나믹 포트 포워딩 (SOCKS 프록시)

로컬에 SOCKS 프록시 서버를 생성하여 모든 트래픽을 SSH 터널을 통해 전달한다.

ssh -D [로컬포트] user@server
# SOCKS 프록시 생성
ssh -D 1080 user@proxy-server
  • 브라우저 SOCKS 프록시 설정: localhost:1080
  • 모든 웹 트래픽이 proxy-server를 경유한다
  • 회사 내부망 접근, 지역 제한 우회에 활용

4.1 브라우저 설정

Firefox: Settings → Network Settings → Manual Proxy → SOCKS Host: localhost, Port: 1080

5 SSH Config에서 포트 포워딩

자주 사용하는 포트 포워딩을 Config에 미리 저장한다.

# ~/.ssh/config

# DB 터널
Host db-tunnel
    HostName db-server.company.com
    User dbadmin
    LocalForward 3306 localhost:3306

# Jupyter 터널
Host jupyter-tunnel
    HostName ml-server.company.com
    User researcher
    LocalForward 8888 localhost:8888

# SOCKS 프록시
Host proxy
    HostName proxy.company.com
    User proxyuser
    DynamicForward 1080
ssh db-tunnel      # 접속만 하면 3306 포워딩 자동 설정
ssh proxy          # 접속만 하면 SOCKS 프록시 자동 생성

6 Bastion Host (Jump Server)

6.1 아키텍처

Bastion Host는 외부에서 내부 네트워크에 접근하기 위한 유일한 진입점 역할을 한다.

인터넷                    방화벽              내부 네트워크
   │                          │                      │
   │                     ┌────────┐                  │
   │──── SSH (22) ─────> │ Bastion│                  │
   │                     │ Host   │                  │
   │                     └────┬───┘                  │
   │                          │   SSH                │
   │                          ├──────────> Server 1  │
   │                          ├──────────> Server 2  │
   │                          └──────────> Server 3  │
  • 외부에서 내부 서버에 직접 접속 불가
  • 모든 접속은 Bastion Host를 경유
  • 접속 로그를 Bastion에서 중앙 관리

6.2 ProxyJump 설정

# ~/.ssh/config

Host bastion
    HostName bastion.company.com
    User bastion-user
    IdentityFile ~/.ssh/bastion_key

# 내부 서버 (Private IP만 있음)
Host internal-db
    HostName 10.0.5.10
    User dbadmin
    IdentityFile ~/.ssh/internal_key
    ProxyJump bastion

Host internal-web
    HostName 10.0.5.20
    User webadmin
    IdentityFile ~/.ssh/internal_key
    ProxyJump bastion
ssh internal-db    # bastion 경유하여 자동 접속

6.3 다단계 접속 (멀티홉)

Host bastion
    HostName 40.100.50.20
    User bastion-user

Host jump-server
    HostName 10.0.1.100
    User jump-user
    ProxyJump bastion

Host target-vm
    HostName 10.0.2.50
    User vmuser
    ProxyJump jump-server
ssh target-vm
# bastion → jump-server → target-vm 순으로 자동 연결

6.4 명령줄에서 직접 사용

# -J 옵션 (SSH 7.3+)
ssh -J bastion-user@bastion.company.com internal-user@10.0.1.100

# 여러 점프 서버
ssh -J jump1@host1,jump2@host2 user@final-server

7 Agent Forwarding

로컬의 SSH 키를 원격 서버에서도 사용할 수 있게 한다. 키 파일을 서버에 복사하지 않아도 된다.

# 명령줄
ssh -A user@server

# Config
Host dev-server
    HostName 20.196.144.16
    User ubuntu
    ForwardAgent yes

활용 사례: VM에 SSH 접속 후, VM에서 GitHub에 git push할 때 로컬의 GitHub SSH 키를 사용한다.

경고

Agent Forwarding은 신뢰할 수 없는 서버에서는 사용하지 않는다. 서버의 root 사용자가 agent 소켓에 접근하여 키를 악용할 수 있다.

8 X11 포워딩

원격 서버의 GUI 애플리케이션을 로컬에서 표시한다.

ssh -X user@server
# 접속 후
firefox &          # 원격 서버의 Firefox가 로컬 화면에 표시

서버 설정 (/etc/ssh/sshd_config):

X11Forwarding yes

9 요약

유형 명령어 용도
로컬 포워딩 ssh -L 3306:localhost:3306 user@db 원격 DB를 로컬에서 접근
리모트 포워딩 ssh -R 8080:localhost:3000 user@server 로컬 서버를 외부에 공개
다이나믹 포워딩 ssh -D 1080 user@proxy SOCKS 프록시
백그라운드 터널 ssh -f -N -L ... 셸 없이 포워딩만 유지
Jump Server ssh -J bastion user@internal Bastion 경유 접속
Agent 포워딩 ssh -A user@server 로컬 키를 원격에서 사용
X11 포워딩 ssh -X user@server 원격 GUI 표시

Subscribe

Enjoy this blog? Get notified of new posts by email: