SSH 터널링 완전 정복 — 원격 서버 개발 환경 구축

게시일: 2025년 6월 24일 · 14분 읽기

방화벽 뒤의 서버에 접근해야 할 때

우리 회사의 데이터베이스 서버는 방화벽 뒤에 있다. VPN으로 접근할 수 있지만, VPN은 느리다. 게다가 로컬에서 직접 DB에 연결해서 개발하고 싶었다. 이때 SSH 터널링이 답이었다.

SSH 터널을 사용하면서 VPN 없이도 보안 연결을 할 수 있고, 속도도 훨씬 빠르다. 방법을 정리하겠다.

로컬 포트 포워딩 (Local Port Forwarding)

가장 기본적인 방식이다. 로컬의 포트를 원격 서버의 포트로 연결한다.

<?xml version="1.0"?>
# 형식
ssh -L [local-port]:[remote-host]:[remote-port] [ssh-user]@[ssh-host]

# 예: 로컬 3306 포트를 원격 DB 서버의 3306에 연결
ssh -L 3306:db.internal.com:3306 user@jump-host.example.com

# 이제 로컬에서
mysql -h localhost -P 3306 -u dbuser -p

# -N 플래그로 셸 실행 안 함
ssh -L 3306:db.internal.com:3306 -N user@jump-host.example.com

이제 로컬의 localhost:3306이 원격 DB와 연결된다. 마치 로컬에 DB가 있는 것처럼 작동한다.

원격 포트 포워딩 (Remote Port Forwarding)

반대로 원격 서버에서 로컬 포트에 접근하고 싶을 때:

<?xml version="1.0"?>
# 형식
ssh -R [remote-port]:[local-host]:[local-port] [user]@[remote-host]

# 예: 원격 서버의 8000 포트를 로컬의 3000 포트로 연결
ssh -R 8000:localhost:3000 user@remote-server.com

# 이제 원격 서버에서
curl localhost:8000  # 로컬의 3000 포트로 접근됨

디버깅할 때 유용하다. 원격 서버의 테스트 스크립트가 로컬의 개발 서버에 요청을 보낼 수 있다.

동적 포트 포워딩 (Dynamic Port Forwarding)

모든 트래픽을 SSH를 통해 터널링하고 싶을 때:

<?xml version="1.0"?>
# SOCKS 프록시 생성
ssh -D 1080 user@jump-host.example.com

# 이제 로컬의 1080 포트가 SOCKS 프록시 역할
# 브라우저나 앱에서 프록시 설정:
# SOCKS 호스트: localhost
# 포트: 1080

# 또는 curl에서
curl --socks5-hostname localhost:1080 http://internal.example.com

ProxyJump와 Jump Host

여러 서버를 거쳐서 접근할 때:

<?xml version="1.0"?>
# ssh/config 파일에서
Host db-server
  HostName db.internal.com
  User postgres
  ProxyJump jump-host

Host jump-host
  HostName jump.example.com
  User ubuntu
  IdentityFile ~/.ssh/jump_key

# 이제 바로 접근 가능
ssh db-server  # 자동으로 jump-host를 거쳐서 연결됨

# 로컬 포트 포워딩도 자동으로 jump-host를 거친다
ssh -L 3306:db-server:3306 db-server

VS Code Remote SSH

SSH 터널을 VS Code와 통합하면 정말 강력하다:

<?xml version="1.0"?>
# ssh/config
Host remote-dev
  HostName dev.example.com
  User developer
  ProxyJump jump-host
  IdentityFile ~/.ssh/dev_key
  ServerAliveInterval 60
  ServerAliveCountMax 3

// VS Code: Remote Explorer에서 remote-dev 선택
// 자동으로 SSH 연결되고, 원격 서버의 코드를 로컬에서 편집
// 터미널도 원격 서버의 터미널

지속적인 연결 (Persistent Tunnel)

항상 켜둔 터널이 필요할 때:

<?xml version="1.0"?>
# Systemd 서비스로 등록 (Linux)
# ~/.config/systemd/user/ssh-tunnel.service
[Unit]
Description=SSH Tunnel to DB Server
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/ssh -N -L 3306:db.internal.com:3306 user@jump-host.example.com
Restart=always
RestartSec=5

[Install]
WantedBy=default.target

# 활성화
systemctl --user enable ssh-tunnel.service
systemctl --user start ssh-tunnel.service

macOS에서는 launchd를 쓴다:

<?xml version="1.0"?>
# ~/Library/LaunchAgents/com.user.ssh-tunnel.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.user.ssh-tunnel</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/ssh</string>
    <string>-N</string>
    <string>-L</string>
    <string>3306:db.internal.com:3306</string>
    <string>user@jump-host.example.com</string>
  </array>
  <key>KeepAlive</key>
  <true/>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

# 로드
launchctl load ~/Library/LaunchAgents/com.user.ssh-tunnel.plist

보안 고려사항

SSH 터널을 안전하게 사용하려면:

<?xml version="1.0"?>
# ssh/config에서 보안 강화
Host *
  StrictHostKeyChecking accept-new
  AddKeysToAgent yes
  UseKeychain yes
  IdentitiesOnly yes

Host jump-host
  HostName jump.example.com
  User ubuntu
  IdentityFile ~/.ssh/id_jump_only
  # 특정 포트만 열기
  LocalForward 3306 db.internal.com:3306

터널 모니터링

<?xml version="1.0"?>
# 활성 터널 확인
ps aux | grep ssh

# 더 자세한 정보
lsof -i :3306  # 3306 포트 사용 중인 프로세스

# SSH 연결 로그
ssh -v -L 3306:db.internal.com:3306 user@jump-host.example.com

실전 예제

우리 회사에서 사용하는 설정:

<?xml version="1.0"?>
# ssh/config
Host prod-jump
  HostName jump.prod.example.com
  User devops
  IdentityFile ~/.ssh/prod_key
  ControlMaster auto
  ControlPath ~/.ssh/control-%h-%p-%r
  ControlPersist 600

Host prod-db
  HostName postgres.internal
  ProxyJump prod-jump
  User postgres
  IdentityFile ~/.ssh/prod_db_key

Host prod-api
  HostName api.internal
  ProxyJump prod-jump
  User ubuntu
  IdentityFile ~/.ssh/prod_api_key

Host dev-*
  ProxyJump prod-jump

# 터널 설정
LocalForward 5432 postgres.internal:5432  # DB
LocalForward 6379 redis.internal:6379     # Redis
LocalForward 9200 elasticsearch.internal:9200  # ES

마무리

SSH 터널링은 보안과 편의성을 동시에 제공한다. VPN보다 빠르고, 필요한 서비스만 로컬에 노출할 수 있다. 원격 개발 환경 구축에 필수적인 도구다.

처음엔 복잡해 보이지만, 한 번 설정해두면 정말 편하다. 특히 마이크로서비스 아키텍처에서는 여러 서버를 접근해야 하니까, 이런 설정이 있으면 개발 생산성이 크게 향상된다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.