SSH ポートフォワーディング(トンネリング)
『SSH』のポートフォワーディング(トンネリング)機能を使うと、暗号化されたSSH接続を通じて任意のTCPポートを安全に転送できます。外部に直接公開できないデータベースへの安全な接続、踏み台サーバー経由のアクセス、ローカルの開発サーバーを一時的に外部へ公開するなど、幅広いユースケースで活用されます。ポートフォワーディングには「ローカル転送(-L)」「リモート転送(-R)」「ダイナミック転送(-D)」の3種類があります。
構文
# -----------------------------------------------
# ローカルポートフォワーディング(-L)
# -----------------------------------------------
# ssh -L {ローカルポート}:{転送先ホスト}:{転送先ポート} {SSHユーザー}@{踏み台サーバー}
# → ローカルマシンの指定ポートへの接続を、踏み台サーバー経由で転送先ホストへ届けます
# → ローカルから直接アクセスできないリモートのDBやサービスに安全に接続できます
# 例: ssh -L 3306:db.internal:3306 ginoza@bastion.example.com
# -----------------------------------------------
# リモートポートフォワーディング(-R)
# -----------------------------------------------
# ssh -R {リモートポート}:{ローカルホスト}:{ローカルポート} {SSHユーザー}@{リモートサーバー}
# → リモートサーバーの指定ポートへの接続を、SSH接続を通じてローカルマシンへ転送します
# → ローカルの開発サーバーを外部から一時的にアクセス可能にする場合などに使います
# 例: ssh -R 8080:localhost:3000 ginoza@public.example.com
# -----------------------------------------------
# ダイナミックポートフォワーディング(-D)
# -----------------------------------------------
# ssh -D {ローカルポート} {SSHユーザー}@{SSHサーバー}
# → ローカルに SOCKS5 プロキシを立ち上げ、リモートサーバー経由で通信をルーティングします
# → ブラウザのプロキシ設定と組み合わせて VPN 的な用途で使えます
# 例: ssh -D 1080 ginoza@bastion.example.com
構文一覧
| オプション | 用途 | 説明 |
|---|---|---|
-L | ローカルポートフォワーディング | ローカルマシンのポートへの接続を踏み台サーバー経由でリモートホストへ転送します。DBへの安全な接続などに使用します。 |
-R | リモートポートフォワーディング | リモートサーバーのポートへの接続をSSHトンネル経由でローカルマシンへ転送します。ローカルサービスの一時的な外部公開などに使用します。 |
-D | ダイナミックポートフォワーディング | ローカルにSOCKS5プロキシを立ち上げます。リモートサーバー経由で任意の宛先に接続できます。 |
-N | コマンド実行なし | リモートでシェルコマンドを実行せず、トンネルだけを維持します。バックグラウンド起動時に-fと組み合わせて使います。 |
-f | バックグラウンド実行 | SSH接続をバックグラウンドに移してコマンドを実行します。-Nと組み合わせてトンネル専用プロセスとして常駐させられます。 |
-g | 他ホストからの接続を許可 | -Lや-Dで開いたポートをローカルマシン以外からも利用可能にします。チーム内で共有する場合などに使用します。 |
-p | SSHポート指定 | 踏み台サーバーのSSHポートが22番以外の場合に指定します。 |
-i | 秘密鍵の指定 | 使用する秘密鍵ファイルを明示的に指定します。複数の鍵を使い分ける場合に有効です。 |
使用例
ローカルポートフォワーディング(DB接続)
# ----------------------------------------------- # 踏み台サーバー経由でリモートの MySQL に接続する # ----------------------------------------------- # # 構成イメージ: # ローカル:3306 → SSH トンネル → bastion.example.com → db.internal:3306 # # - bastion.example.com : 踏み台(踏み台 = 宜野座伸元が管理するサーバーと仮定) # - db.internal : 内部ネットワークの MySQL サーバー # - ginoza : 踏み台への SSH ユーザー名 # ローカルの 3306 番ポートへの接続を db.internal:3306 へ転送するトンネルを開きます # -N: リモートでコマンドを実行しない # -f: バックグラウンドで起動する ssh -N -f -L 3306:db.internal:3306 ginoza@bastion.example.com # トンネルが確立したらローカルの 3306 番に対して mysql コマンドで接続します # リモートのデータベースにローカルから直接アクセスしているのと同じように操作できます mysql -h 127.0.0.1 -P 3306 -u sibyl_admin -p
実行するコマンドは次の通りです。
$ ssh -N -f -L 3306:db.internal:3306 ginoza@bastion.example.com $ mysql -h 127.0.0.1 -P 3306 -u sibyl_admin -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 42 Server version: 8.0.36 MySQL Community Server - GPL mysql>
リモートポートフォワーディング(外部公開)
# ----------------------------------------------- # ローカルの開発サーバーを外部から一時的に公開する # ----------------------------------------------- # # 構成イメージ: # 外部ユーザー → public.example.com:8080 → SSH トンネル → localhost:3000 # # - public.example.com : グローバル IP を持つリモートサーバー # (霜月美佳が管理するデモ用サーバーと仮定) # - localhost:3000 : ローカルで動いている開発用 Web アプリ # - shimatsuki : リモートサーバーへの SSH ユーザー名 # リモートサーバーの 8080 番ポートへの接続をローカルの 3000 番へ転送するトンネルを開きます # -N: リモートでコマンドを実行しない # -f: バックグラウンドで起動する ssh -N -f -R 8080:localhost:3000 shimatsuki@public.example.com # 外部からは http://public.example.com:8080/ でローカルのアプリにアクセスできます # ※リモートサーバーの GatewayPorts を yes に設定している場合は外部からも接続可能です
実行するコマンドは次の通りです。
$ ssh -N -f -R 8080:localhost:3000 shimatsuki@public.example.com $ curl -I http://public.example.com:8080/ HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8 Server: WP-P Dev Server/1.0
ダイナミックポートフォワーディング(SOCKS5プロキシ)
# ----------------------------------------------- # SOCKS5 プロキシを経由してブラウジングする # ----------------------------------------------- # # 構成イメージ: # ローカルアプリ(SOCKS5:1080) → SSH トンネル → proxy.example.com → 任意の宛先 # # - proxy.example.com : SSH 接続先(常守朱が管理するプロキシサーバーと仮定) # - tsunemori : SSH ユーザー名 # ローカルの 1080 番ポートに SOCKS5 プロキシを立ち上げます ssh -N -f -D 1080 tsunemori@proxy.example.com # curl で SOCKS5 プロキシ経由のリクエストを送る例です curl --socks5 127.0.0.1:1080 http://example.internal/api/status
実行するコマンドは次の通りです。
$ ssh -N -f -D 1080 tsunemori@proxy.example.com
$ curl --socks5 127.0.0.1:1080 http://example.internal/api/status
{"status":"ok","inspector":"Tsunemori Akane","division":1}
~/.ssh/config に設定を記述してコマンドを短くする
# ----------------------------------------------- # ~/.ssh/config にトンネル設定を書いておくと # 毎回長いオプションを入力せずに済みます # ----------------------------------------------- # Host エイリアスに対して LocalForward を設定します # この設定を記述した後は "ssh db-tunnel" だけで接続できます # ~/.ssh/config の記述例: # # Host db-tunnel # HostName bastion.example.com # User ginoza # IdentityFile ~/.ssh/id_ed25519_bastion # LocalForward 3306 db.internal:3306 # ServerAliveInterval 60 # ServerAliveCountMax 3 # 設定後のコマンドはシンプルになります ssh -N -f db-tunnel # トンネルのプロセス ID を確認して終了させます ps aux | grep 'ssh -N'
実行するコマンドは次の通りです。
$ ssh -N -f db-tunnel $ ps aux | grep 'ssh -N' ginoza 12345 0.0 0.0 ssh -N -f db-tunnel $ kill 12345
概要
SSHポートフォワーディングは、既存のSSH接続の上に任意のTCPトラフィックを流す機能です。ローカルフォワーディング(-L)は「自分のマシンからリモートの非公開リソースへ安全にアクセスする」用途で最もよく使われます。データベース(MySQL・PostgreSQL など)やRedisのような内部向けサービスへの接続を、踏み台サーバー経由で安全に確立できます。リモートフォワーディング(-R)は逆方向で、「外部からローカルマシンのサービスへアクセスしてもらう」用途に使います。開発中のWebアプリを上司やクライアントに確認してもらう際などに便利です。ただし、リモートサーバーの /etc/ssh/sshd_config で GatewayPorts yes が設定されていないと外部からのアクセスは許可されないため注意が必要です。バックグラウンドで常駐させる場合は -f -N の組み合わせが定番です。頻繁に使うトンネル設定は ~/.ssh/config に LocalForward / RemoteForward として記述しておくことで、コマンドを毎回入力せずに済みます。SSH接続全般の基本については ssh コマンド基本 のページを参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。