2026年7月7日
2026年7月7日
SSHポートフォワーディング(-L/-R/-D)の使い方|トンネルの張り方からサーバー設定・autosshでの常駐まで
SSHポートフォワーディングは、SSHの暗号化された接続の中に別の通信を通す仕組みで、「SSHトンネル」とも呼ばれます。外部に公開していないデータベースへ手元のPCから接続する、社内にしかない管理画面を一時的に見る、といった用途で使います。この記事では、-L(ローカル)、-R(リモート)、-D(ダイナミック)の3種類の使い分けと、サーバー側で許可・制限する sshd_config の設定、autosshとsystemdでトンネルを常駐させる方法までを解説します(2026年10月現在の OpenSSH を前提にしています)。
3種類のフォワーディングの違い
3つの違いは「どちら側で待ち受け、どちら側から接続しにいくか」です。
- ローカルフォワーディング(-L):手元のPCでポートを待ち受け、届いた通信をSSHサーバー経由で転送先に送ります。手元からサーバーの奥にあるサービスへ接続したいときに使います。
- リモートフォワーディング(-R):SSHサーバー側でポートを待ち受け、届いた通信を手元のPC(またはその先)に送ります。外から手元の環境に入ってもらいたいときに使います。
- ダイナミックフォワーディング(-D):手元にSOCKSプロキシを立て、接続先をアプリケーションごとに動的に決めます。サーバーを出口にしてWebを閲覧するような使い方です。
どれもSSHでログインできる権限があれば使えますが、サーバー側で禁止されていることもあります。動かないときは後述のサーバー設定を確認してください。
ローカルフォワーディング(-L)でサーバーのDBに接続する
WordPressのデータベース(MySQL/MariaDB)は、安全のため 127.0.0.1 でのみ待ち受け、外部からは接続できない設定にするのが一般的です。この状態でも、SSHトンネルを使えば手元のデータベースクライアントから接続できます。
# 書式: ssh -L [待ち受けアドレス:]待ち受けポート:転送先ホスト:転送先ポート ユーザー@SSHサーバー
ssh -N -L 13306:127.0.0.1:3306 deploy@server.example.com
この状態で別のターミナルから手元の13306番に接続すると、サーバー上の3306番につながります。
mysql -h 127.0.0.1 -P 13306 -u wp_user -p
ここで2つのつまずきどころがあります。1つ目は、転送先の 127.0.0.1 は「SSHサーバーから見た」アドレスだという点です。手元のPCのことではありません。サーバーとは別のDBサーバー(例: 10.0.0.5)に、SSHサーバーを踏み台にして接続することもでき、その場合は 13306:10.0.0.5:3306 と書きます。2つ目は、mysqlクライアントで -h localhost と書くと、TCPではなくUNIXソケットで接続しようとしてトンネルを通らない点です。トンネル経由では 127.0.0.1 を指定します。
-N はリモートでコマンドを実行せず転送だけを行うオプションです。待ち受けポートに1024未満を指定すると、手元で管理者権限が必要になるため、10000番以上など空いている番号を使うのが無難です。手元で待ち受けているかは、Linux/macOSなら ss -tln や lsof -i :13306 で確認できます。
待ち受けアドレスに注意する
-L の待ち受けは、既定では手元のループバック(自分自身)だけです。同じネットワークの別のPCからもトンネルを使わせたい場合は -L 0.0.0.0:13306:127.0.0.1:3306 のように待ち受けアドレスを指定しますが、そのネットワーク上の誰でも転送先に接続できる状態になります。カフェなどの共有ネットワークでは使わず、必要な場面に限ってください。
リモートフォワーディング(-R)で手元のサービスを見せる
手元のPCで動かしている開発中のサイトを、一時的にサーバー経由で確認してもらう場合などに使います。
# サーバーの8080番に届いた通信を、手元の localhost:3000 に転送する
ssh -N -R 8080:localhost:3000 deploy@server.example.com
-R では書式の向きが逆になり、最初のポートがサーバー側の待ち受け、後ろが手元から見た転送先です。
既定では、サーバー側の待ち受けもサーバーのループバックだけになり、サーバーの外からは接続できません。外部から8080番に直接接続させたい場合は、サーバーの sshd_config で GatewayPorts を変更する必要があります。
GatewayPorts no(既定):サーバーのループバックだけで待ち受けるGatewayPorts yes:すべてのアドレスで待ち受けるGatewayPorts clientspecified:クライアントが-R 0.0.0.0:8080:...のように指定したアドレスで待ち受ける
yes にするとすべてのリモートフォワーディングが外部に公開されるため、必要な場合でも clientspecified にして、ファイアウォールで接続元を絞るほうが安全です。多くの場合は GatewayPorts を変えず、サーバー側のNginxなどからループバックの8080番にリバースプロキシするほうが、HTTPSやアクセス制限を組み合わせやすくなります。
ダイナミックフォワーディング(-D)でSOCKSプロキシにする
ssh -N -D 1080 deploy@server.example.com
手元の1080番がSOCKSプロキシになり、ブラウザなどのプロキシ設定で localhost:1080(SOCKS v5)を指定すると、通信はサーバーを出口として送られます。接続元IPアドレスで制限された管理画面を、許可済みのサーバー経由で開くといった用途に使えます。
ブラウザによっては、名前解決(DNS)だけがプロキシを通らず手元で行われます。Firefoxでは、SOCKS v5使用時にDNSもプロキシ経由にする設定を有効にしてください。コマンドラインで試すときは、curlの --socks5-hostname を使うと名前解決もサーバー側で行われます。
curl --socks5-hostname localhost:1080 https://example.com/
~/.ssh/config に書いて毎回の入力を省く
よく使うトンネルは、SSHの設定ファイルにまとめておくと ssh 名前 だけで張れます。
Host wp-db-tunnel
HostName server.example.com
User deploy
IdentityFile ~/.ssh/id_ed25519
LocalForward 13306 127.0.0.1:3306
ServerAliveInterval 30
ServerAliveCountMax 3
ExitOnForwardFailure yes
ssh -N wp-db-tunnel
LocalForward のほかに RemoteForward、DynamicForward も同じように書けます。ExitOnForwardFailure yes は、ポートがすでに使われているなどで転送を設定できなかったときにSSH自体を終了させる設定です。これがないと、ログインには成功したのにトンネルだけ張れていない状態に気づきにくくなります。踏み台サーバーを経由する場合は ProxyJump 踏み台名 を追加すると、踏み台の先のサーバーに対して同じようにトンネルを張れます。
サーバー側で許可・制限する(sshd_config)
サーバーを管理する立場では、フォワーディングを「誰に」「どこまで」許すかを決めておきます。関係する主な設定は次のとおりです。
AllowTcpForwarding:yes(既定)、no、local(-Lのみ許可)、remote(-Rのみ許可)を指定できます。PermitOpen:-Lや-Dで接続できる転送先を127.0.0.1:3306のように限定します。PermitListen:-Rでサーバー側に待ち受けられるポートを限定します。GatewayPorts:前述のリモートフォワーディングの公開範囲です。
ユーザーごとに変えたい場合は Match ブロックを使います。たとえば、通常はフォワーディングを禁止し、DB接続用のユーザーにだけ3306番への転送を許す設定は次のとおりです。
AllowTcpForwarding no
Match User dbtunnel
AllowTcpForwarding local
PermitOpen 127.0.0.1:3306
X11Forwarding no
Match ブロックは次の Match 行かファイルの終わりまでの設定に適用されるので、ファイルの末尾に書きます。変更後は sudo sshd -t で文法を確認してから再起動または再読み込みします。文法エラーのまま再起動すると、SSHで入れなくなるおそれがあるため、作業中のSSH接続は閉じずに残し、別の接続でログインできることを確かめてから切断してください。
鍵ごとに制限する方法もあります。~/.ssh/authorized_keys の公開鍵の行頭に restrict,port-forwarding,permitopen="127.0.0.1:3306" のように書くと、その鍵ではシェル操作などを禁止しつつ、指定の転送だけを許可できます。
autosshとsystemdでトンネルを常駐させる
SSHの接続は、ネットワークの瞬断やサーバーの再起動で切れます。バックアップの転送やアプリケーションからのDB接続など、トンネルを張りっぱなしにしたい場合は、切断時に自動で張り直す仕組みが必要です。autosshはSSHを監視し、終了したら再起動するツールで、Debian/Ubuntuでは sudo apt install autossh で導入できます。
autossh -M 0 -N \
-o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-o "ExitOnForwardFailure yes" \
-L 13306:127.0.0.1:3306 deploy@server.example.com
-M 0 はautosshの監視用ポートを使わず、SSHの ServerAliveInterval による死活確認に任せる指定です。この例では30秒ごとに応答を確認し、3回続けて応答がなければSSHが終了し、autosshが張り直します。
サーバー起動時に自動で開始したい場合は、systemdのユニットにします。systemdで管理する場合は -f(バックグラウンド化)を付けず、フォアグラウンドで動かします。
# /etc/systemd/system/wp-db-tunnel.service
[Unit]
Description=SSH tunnel to WordPress DB
After=network-online.target
Wants=network-online.target
[Service]
User=tunnel
Environment=AUTOSSH_GATETIME=0
ExecStart=/usr/bin/autossh -M 0 -N -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -o "ExitOnForwardFailure yes" -i /home/tunnel/.ssh/id_ed25519 -L 13306:127.0.0.1:3306 dbtunnel@server.example.com
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now wp-db-tunnel.service
systemctl status wp-db-tunnel.service
AUTOSSH_GATETIME=0 は、起動直後の接続失敗も再試行の対象にする設定で、ネットワークの準備が遅れる起動時に役立ちます。無人で接続するため、鍵はパスフレーズなしにせざるを得ないことが多く、前述の restrict や PermitOpen で、その鍵でできることを転送だけに絞っておくことが重要です。初回は手動で一度接続し、ホスト鍵を known_hosts に登録しておかないと、確認待ちで接続できません。
まとめ
-Lは手元で待ち受けてサーバー側へ、-Rはサーバーで待ち受けて手元側へ、-DはSOCKSプロキシとして転送する-Lの転送先はSSHサーバーから見たアドレスで、mysqlクライアントはlocalhostではなく127.0.0.1を指定する- 待ち受けは既定でループバックのみ。外部公開は
GatewayPortsやバインドアドレスで明示的に行い、範囲を最小限にする - サーバー側は
AllowTcpForwarding・PermitOpen・PermitListenとMatchで、許可する相手と転送先を絞る - 常駐させるトンネルはautossh(
-M 0)とsystemdで張り直しを自動化し、専用ユーザーと制限付きの鍵を使う