3.

SSH ポートフォワーディング (Local/Remote/Dynamic) 完全ガイド

編集
この記事の要点
  • SSH ポートフォワーディング = SSH 接続のトンネルを使って他の TCP 通信を中継する機能
  • Local Forward (-L): ローカル → リモート (例: 踏み台越しの DB アクセス)
  • Remote Forward (-R): リモート → ローカル (例: 自宅マシンを社外公開)
  • Dynamic Forward (-D): SOCKS プロキシ (例: VPN 代替)
  • 永続化は autossh、踏み台越しは ProxyJump (-J)、サーバ側は AllowTcpForwarding yes

SSH ポートフォワーディングとは

SSH 接続そのものの暗号化されたトンネルを利用して、任意の TCP 通信を中継する機能です。VPN を立てるよりお手軽に、ファイアウォール越しの DB アクセスや、社内サーバへのリモート公開を実現できます。

形式は 3 種類あります:

種別オプション方向用途
Local Forward-Lクライアント → リモート踏み台越しの DB / Web アクセス
Remote Forward-Rリモート → クライアント自宅 PC を外部公開 / 逆 SSH
Dynamic Forward-D動的 (SOCKS)SOCKS プロキシで全 TCP 中継

Local Forward (-L)

クライアントが受け付けたポートへの接続を、SSH トンネル経由でリモート側の指定先に転送します。踏み台経由で DB に接続したいケースの定番。

構文

ssh -L [bind_address:]local_port:dest_host:dest_port user@ssh_server

# 例: ローカル 13306 → 踏み台経由で internal-db:3306
ssh -L 13306:internal-db.example.com:3306 user@bastion.example.com

# 別端末から
mysql -h 127.0.0.1 -P 13306 -u dbuser -p
# → 実際は bastion 経由で internal-db に到達

# 複数ポート同時
ssh -L 13306:db:3306 -L 16379:redis:6379 user@bastion

動作イメージ

[mysql client]
     ↓ 127.0.0.1:13306
[OpenSSH client] ─── SSH 暗号化トンネル ───→ [bastion sshd]
                                                   ↓
                                          internal-db:3306

Remote Forward (-R)

リモートサーバ側のポートで接続を受け、SSH トンネル経由でクライアント側に転送します。NAT 内の自宅マシンを外部公開したい用途で使います。

ssh -R [bind_address:]remote_port:dest_host:dest_port user@ssh_server

# 例: 自宅 Web (8080) を public.example.com:9080 で公開
ssh -R 9080:localhost:8080 user@public.example.com

# 外部から
curl http://public.example.com:9080/
# → 自宅 PC の localhost:8080 に到達

# 公開時の注意: デフォルトは loopback バインド (127.0.0.1)
# 外部から見せるには /etc/ssh/sshd_config で
#   GatewayPorts yes (または clientspecified)

Dynamic Forward (-D)

クライアント側にローカル SOCKS プロキシを立て、すべての TCP を SSH トンネル経由で送り出します。VPN 代替として便利:

ssh -D 1080 user@bastion.example.com
# → 127.0.0.1:1080 で SOCKS5 プロキシが起動

# ブラウザの SOCKS プロキシに設定
# Firefox: 設定 → ネットワーク → 手動プロキシ → SOCKS Host: 127.0.0.1, Port: 1080

# curl で使う
curl --socks5 127.0.0.1:1080 http://internal.example.com/

# Chrome をプロキシ起動
google-chrome --proxy-server="socks5://127.0.0.1:1080"

~/.ssh/config に書く

毎回長いコマンドを打たずに済むよう、設定ファイルに記述するのが定石:

# ~/.ssh/config
Host bastion
    HostName bastion.example.com
    User myuser
    IdentityFile ~/.ssh/id_ed25519

# DB トンネル付き
Host db-tunnel
    HostName bastion.example.com
    User myuser
    LocalForward 13306 internal-db.example.com:3306
    LocalForward 16379 internal-redis.example.com:6379
    ServerAliveInterval 30
    ServerAliveCountMax 3

# 利用
ssh db-tunnel
# 別端末で
mysql -h 127.0.0.1 -P 13306 -u dbuser -p

ProxyJump (-J) で多段踏み台

従来は ProxyCommand で書いていましたが、OpenSSH 7.3+ では -J (ProxyJump) で簡潔に書けます:

# bastion 経由で db-server に接続
ssh -J user@bastion.example.com user@db-server.internal

# Local Forward と組み合わせ
ssh -J user@bastion.example.com -L 13306:localhost:3306 user@db-server.internal

# ~/.ssh/config
Host db-server
    HostName db-server.internal
    User dbuser
    ProxyJump bastion

バックグラウンド実行と autossh で永続化

SSH 接続が切れるとトンネルも切れます。本番運用では autossh で自動再接続:

# バックグラウンド + パスワード不要
ssh -fN -L 13306:internal-db:3306 user@bastion
# -f: バックグラウンド / -N: コマンド実行しない

# autossh (Ubuntu/Debian)
sudo apt install autossh

autossh -M 0 -fN \
    -o "ServerAliveInterval 30" \
    -o "ServerAliveCountMax 3" \
    -L 13306:internal-db:3306 \
    user@bastion

# systemd で永続化
# /etc/systemd/system/ssh-tunnel.service
# [Unit]
# Description=SSH Tunnel to DB
# After=network.target
#
# [Service]
# User=myuser
# ExecStart=/usr/bin/autossh -M 0 -N -L 13306:internal-db:3306 user@bastion
# Restart=always
#
# [Install]
# WantedBy=multi-user.target

サーバ側設定 (sshd_config)

SSH サーバ側で forwarding を許可する必要があります:

# /etc/ssh/sshd_config
AllowTcpForwarding yes          # ポートフォワーディング許可 (デフォルト yes)
GatewayPorts no                 # Remote Forward を 0.0.0.0 にバインドするか
                                # no    : loopback のみ
                                # yes   : すべて
                                # clientspecified : ssh -R 0.0.0.0:port 指定可
PermitTunnel yes                # tun デバイス転送 (本格的 VPN 用、稀)

AllowAgentForwarding yes        # エージェント転送
X11Forwarding yes               # GUI 転送

# 反映
sudo systemctl reload sshd

Windows での利用

OpenSSH for Windows

# Windows 10+ には標準搭載 (機能のオプション機能から OpenSSH クライアント)
ssh -L 13306:internal-db:3306 user@bastion.example.com

PuTTY / Plink

PuTTY GUI: Connection → SSH → Tunnels で設定。コマンドラインなら plink:

plink.exe -L 13306:internal-db:3306 user@bastion.example.com -i C:\Users\me\.ssh\id_ed25519.ppk

# .ppk は puttygen で OpenSSH 鍵から変換

VS Code Remote-SSH

Remote - SSH 拡張を入れると、~/.ssh/config に書いたホストにワンクリック接続でき、SSH 経由でフォルダを開いて開発できます。ポートフォワーディングも自動で行われ (ターミナル下部の PORTS タブ)、Web アプリ開発に便利。

典型ユースケース

ユースケースコマンド
踏み台経由で MySQL 接続ssh -L 13306:db:3306 user@bastion
本番 Redis をローカル接続ssh -L 16379:redis:6379 user@bastion
K8s API への kubectlssh -L 6443:k8s-api:6443 user@bastion
自宅 Web を一時的に外部公開ssh -R 9080:localhost:8080 user@vps
VPN なしで社内 Web 閲覧ssh -D 1080 user@bastion + ブラウザ SOCKS5
X11 GUI アプリを転送ssh -X user@server + 別途 X サーバ

FAQ

Q: channel 3: open failed: administratively prohibited
A: サーバ側 AllowTcpForwarding no または Match ブロックで制限されている。/etc/ssh/sshd_config 確認。

Q: bind: Address already in use
A: ローカル側ポートが既に使われている。lsof -i:13306 で確認、別ポートに変更。

Q: 接続がすぐ切れる
A: ServerAliveInterval 30 + ServerAliveCountMax 3 を設定。NAT セッションタイムアウト対策。

Q: トンネルを他マシンからも使わせたい
A: ssh -L 0.0.0.0:13306:db:3306 ... または GatewayPorts yesセキュリティに注意、社内ネットのみで使用すること。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. TeraTerm
  2. putty
  3. PortFowarder