
sshroute v0.2.11
ネットワーク認識型SSHルーター - アクティブなVPNやネットワークに基づいて、異なるIP/ポート/キー/踏み台ホストへ接続をルーティングします
sshroute
ネットワーク対応SSHルーター。アクティブなネットワークやVPNを検出し、~/.ssh/config に触れることなく、各SSH接続に対して適切なホスト、ポート、IDファイル、ジャンプホストを自動選択します。
仕組み
論理ホストごとに default プロファイルと、オプションのネットワーク別上書きを一度定義します。接続のたびに sshroute は現在のネットワーク(VPN、オフィスLAN、WireGuardピアなど)を検出し、適切なSSHパラメータを解決した上で、実際の /usr/bin/ssh に処理を引き継ぎます。
ssh myserver
→ sshroute 検出: corp-vpn がアクティブ
→ 解決: 10.100.0.50:2222 via bastion.corp.internal
→ exec /usr/bin/ssh -p 2222 -i ~/.ssh/corp_key -J bastion.corp.internal 10.100.0.50
sshroute を選ぶ理由
ホームラボユーザー向け
あなたのラボにはおそらく少なくとも2つの現実があります。自宅でLAN内にいるか、外出中でWireGuardや別のVPN経由で接続しているかです。問題は ~/.ssh/config がどちらにいるかを認識できないことです。その結果、別々のエイリアス(server-lan、server-vpn)を使ったり、半分の時間しか機能しないジャンプホストを使ったり、あるいはIPを暗記したりすることになります。
sshroute は接続のたびに現在のネットワークを検出することでこれを解決します。WireGuardインターフェースが起動していてピアルートが存在する場合は、トンネルIPに直接接続します。LAN上にいる場合はローカルアドレスを使用します。どちらも到達不能な場合は、パブリックホスト名にフォールバックします。1つのエイリアス、3つの現実、手動切り替えは不要です。
また、透過的にSSHをインターセプトします。一度シャドウモードを設定すれば、git push、rsync、scp はすべて自動的に sshroute 経由で処理されます。ラッパーもシェル関数も考える必要もありません。
企業環境向け
エンタープライズネットワークはさらにひどいものです。パブリックインターネット、サイト間VPN、個人VPNのスプリットトンネル、その内側に異なる環境(dev、staging、prod)ごとに異なるジャンプホストがあり、それぞれに異なるキーがあります。これを ~/.ssh/config で管理するには、巨大な設定ファイル(インフラ変更があると壊れる)か、チームメンバーがそれぞれ異なる方法でメンテナンスするスクリプトを書くかのどちらかです。
sshroute ではルーティングロジックを宣言的に定義し、バージョン管理されたYAMLファイルに保存し、チーム全体で共有できます。同じ設定が全員に機能します。各マシンでアクティブなインターフェースやルートに基づいて、適切なネットワークが自動検出されます。ユーザーは考えなくても、キーやポート、ユーザー、ジャンプホストが解決されます。
比較
| 機能 | ~/.ssh/config | WireGuardのみ | Teleport / Boundary | sshroute |
|---|---|---|---|---|
| 現在のネットワークを検出 | ❌ | ❌ | ❌ | ✅ |
| 最適なパスを自動選択 | ❌ | ❌ | ❌ | ✅ |
| 接続失敗時にフォールバック | ❌ | ❌ | ✅ | ✅ |
| 切断時の自動再接続+再ルーティング | ❌ | ⚠️ トンネルローミング | ⚠️ 固定プロキシ経由 | ✅ |
| 1つのコマンドでどの場所からでも1ホスト | ❌ | ⚠️ VPNが起動している必要あり | ✅ | ✅ |
| 10ホスト×4パスでの設定サイズ | 📄 約600行 | 📄 約600行+VPN設定 | 📄 サーバー側設定 | 📄 約60行 |
| モバイルデバイスのローミング | ⚠️ 手動エイリアス | ⚠️ VPN必須 | ✅ | ✅ |
| ジャンプホストの自動連鎖 | ⚠️ 手動 -J | ➖ 該当なし | ✅ | ✅ |
| scp / rsync / git / Ansible で動作 | ✅ | ✅ | ⚠️ 部分的 | ✅ |
| ターゲットへのサーバー側インストール不要 | ✅ | ❌ | ❌ | ✅ |
| 認証サーバーやデーモン不要 | ✅ | ❌ | ❌ | ✅ |
| クライアントエージェント不要 | ✅ | ❌ | ❌ | ✅ |
| オープンソース、完全セルフホスト | ✅ | ✅ | ⚠️ オープンコア | ✅ |
Teleport と Boundary は異なるカテゴリです。ルーティングに加えてアクセス制御、監査ログ、証明書ベースの認証を追加します。それが必要な場合はそれらを使ってください。sshroute は、中央認証サーバーを運用する運用オーバーヘッドなしにルーティングのインテリジェンスが必要な場合に使用します。
インストール
バイナリダウンロード
GitHub Releases から最新のリリースをダウンロードします。Linux、macOS、Android向けにAMD64およびARM64のバイナリが用意されています。
Go Install
go install github.com/thereisnotime/sshroute@latest
Android (Termux)
GitHub Releases から android_arm64 のtarballをダウンロードし、展開してバイナリを ~/.local/bin に配置します:
mkdir -p ~/.local/bin
curl -Lo "$TMPDIR/sshroute.tar.gz" \
https://github.com/thereisnotime/sshroute/releases/latest/download/sshroute_android_arm64.tar.gz
tar -xzf "$TMPDIR/sshroute.tar.gz" -C ~/.local/bin sshroute
chmod +x ~/.local/bin/sshroute
まだの場合、~/.bashrc または ~/.profile で ~/.local/bin を PATH に追加します:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
または、TermuxのGoを使ってソースからコンパイルします。公式のGoツールチェーンはandroid/arm64バイナリを公開していないため、GOTOOLCHAIN=local を設定してTermuxが提供するものを使います:
GOTOOLCHAIN=local go install github.com/thereisnotime/sshroute@latest
インストール後、Termuxには /usr/bin/ssh がないため、SSHバイナリのパスを設定します:
# ~/.config/sshroute/config.yaml
ssh_binary: /data/data/com.termux/files/usr/bin/ssh
または環境変数を使用:export SSHROUTE_SSH=$(which ssh)
Docker
docker run --rm -v ~/.config/sshroute:/root/.config/sshroute \
ghcr.io/thereisnotime/sshroute network
Podman
podman run --rm -v ~/.config/sshroute:/root/.config/sshroute \
ghcr.io/thereisnotime/sshroute network
SELinux対応システム(Fedora、RHELなど)では、ボリュームフラグに :Z を追加します:
podman run --rm -v ~/.config/sshroute:/root/.config/sshroute:Z \
ghcr.io/thereisnotime/sshroute network
シャドウモード(透過的SSH置き換え)
sshroute を $PATH の早い段階で ssh としてインストールします。ターミナル、git、rsync、scp からのすべてのSSH呼び出しが自動的にインターセプトされます。設定にないホストは変更されずに /usr/bin/ssh に渡されます。
mkdir -p ~/.local/bin
ln -s $(which sshroute) ~/.local/bin/ssh
# ~/.bashrc または ~/.zshrc に追加(まだない場合):
export PATH="$HOME/.local/bin:$PATH"
クイックスタート
# デフォルトプロファイルでホストを追加
sshroute add myserver --host myserver.example.com --user alice --key ~/.ssh/id_ed25519
# VPN固有の上書きを追加
sshroute add myserver --network vpn --host 10.8.0.50 --port 2222 --jump bastion.vpn
# 接続 — ネットワークは自動検出
sshroute connect myserver
# 実行せずに解決されたコマンドをプレビュー
sshroute connect myserver --dry-run
# 現在アクティブなネットワークを表示
sshroute network
コマンド
グローバルフラグ
これらのフラグはすべてのコマンドに適用されます:
| フラグ | 環境変数 | デフォルト | 説明 |
|---|---|---|---|
--config | SSHROUTE_CONFIG | ~/.config/sshroute/config.yaml | 設定ファイルのパス |
-o, --output | table | 出力形式:table、json、yaml | |
-v, --verbose | SSHROUTE_VERBOSE=1 | false | デバッグログをstderrに出力 |
--dry-run | false | 実行せずに解決されたSSHコマンドを表示 |
init
コメント付きのサンプルが含まれたスターター設定ファイルを作成します。ファイルが既に存在する場合は失敗します。
| フラグ | デフォルト | 説明 |
|---|---|---|
--force | false | 既存の設定ファイルを上書き |
connect <alias>
アクティブなネットワークを検出し、alias のSSHパラメータを解決し、実際のSSHバイナリを実行します。エイリアスの後にある追加引数は、そのままSSHに渡されます。
| フラグ | デフォルト | 説明 |
|---|---|---|
--fallback | false | すべてのプロファイルを優先順位順に試行し、接続失敗時(exit 255)のみ次のプロファイルをリトライ |
--reconnect | false | 接続を監視し、切断時に自動再接続。そのたびにアクティブなネットワークを再検出し、ルートを再解決 |
--reconnect-delay | 2s | --reconnect 設定時の再接続試行間の待機時間 |
--reconnect を指定すると、sshroute は切断(ラップトップのスリープ、WiFiハンドオフ、ネットワーク間ローミング)があってもsshを生かし続けます。再接続のたびにネットワークを再検出するため、異なるルートに追従します。たとえば、LANでスリープしてホットスポットで起きると、到達不能になったLANアドレスをリトライする代わりに、パブリックルート経由で再接続します。正常なログアウト(exit 0)や認証/リモートコマンドの失敗はループを停止します。実際の接続切断のみが再接続します。再接続は ssh をサブプロセスとして実行するため(--fallback と同様)、sshroute はセッション中常駐します。SIGINT/SIGTERM で停止します。断線によるセッション状態の維持はマルチプレクサ(tmux/zellij)の役目です。--reconnect と -- tmux attach または -- zellij attach -c <name> を組み合わせて、セッションに直接戻ることができます:
sshroute connect myserver --reconnect --fallback -- zellij attach -c work
list
設定されているすべてのホストと、現在のネットワークで使用されるSSHパラメータを一覧表示します。-o table|json|yaml に対応。
add <alias>
ホストを追加するか、既存のホストを更新します。省略されたフラグは現在の値を維持します。異なる --network 値で複数回実行して、ネットワーク別の上書きを構築します。
| フラグ | デフォルト | 説明 |
|---|---|---|
--host | ホスト名またはIPアドレス | |
--port | 22 | SSHポート |
--user | SSHユーザー名 | |
--key | IDファイルへのパス(~ 対応) | |
--jump | ジャンプホスト — -J としてSSHに渡される | |
--network | default | パラメータを書き込むネットワークプロファイル |
remove <alias>
設定から alias のすべてのプロファイルを削除します。
network
現在検出されているネットワークの名前を表示します(該当なしの場合は default)。
network list
すべての設定済みネットワークを、優先度、チェックルール、現在のアクティブ状態と共に一覧表示します。-o table|json|yaml に対応。
network test <name>
ネットワーク name のすべてのチェックを実行し、ルールごとに pass/fail を表示します。検出ロジックのデバッグに便利です。
config
設定ファイルの解決済みパスを表示します。
config edit
$EDITOR(フォールバックは nano)で設定ファイルを開きます。ファイルとその親ディレクトリが存在しない場合は作成します。
resolve <alias>
現在のネットワークで alias に使用されるSSHパラメータを表示します。デバッグやスクリプトに便利です。--network <name> を使用して検出されたネットワークを上書きできます。-o table|json|yaml に対応。
| フラグ | デフォルト | 説明 |
|---|---|---|
--network | 自動検出 | 解決対象となるネットワークプロファイル |
copy <alias> <src> <dst>
connect と同じ解決済みパラメータ(キー、ポート、ジャンプ)を使用して、scp で設定ホストとの間でファイルをコピーします。リモートパスには <alias>:<path> 構文を使用します:
sshroute copy myserver ./local.txt myserver:/remote/path/
sshroute copy myserver myserver:/remote/file.txt ./local/
SSHROUTE_SCP 環境変数で使用する scp バイナリを上書きできます。
version
バージョン、gitコミット、ビルド日、Goランタイム情報を表示します。
update
sshroute を最新のGitHubリリースにその場で更新します。プラットフォーム用のアーカイブをダウンロードし、sha256を checksums.txt に対して検証し、cosign がインストールされている場合はリリースの cosign 署名を検証した後、実行中のバイナリをアトミックに置き換えます。
sshroute update # 最新リリースをダウンロード、検証、インストール
sshroute update --check # 新しいバージョンが利用可能かどうかのみ報告
sshroute update --force # 既に最新でも最新を再インストール
sha256(cosignが存在する場合はcosignも)の検証に失敗した場合、更新は中止され、バイナリは変更されません。これはリリースバイナリのインストールを対象としています。go install やパッケージマネージャーでインストールした場合は、そちらで更新してください。
設定ファイル
デフォルトの場所:~/.config/sshroute/config.yaml
networks:
corp-vpn:
priority: 10 # 低いほど先にチェック
checks:
- type: interface
match: wg0
- type: route
match: 10.100.0.0
office:
priority: 20
checks:
- type: ping
host: 192.168.1.1
timeout: 500ms
hosts:
myserver:
default: # 必須 — 該当するネットワークがない場合に使用
host: myserver.example.com
port: 22
user: alice
key: ~/.ssh/id_ed25519
options: # オプション — SSH -o Key=Value フラグとして渡される
ConnectTimeout: "10"
ServerAliveInterval: "30"
corp-vpn:
host: 10.100.0.50
port: 2222
key: ~/.ssh/corp_key
jump: bastion.corp.internal
options:
ConnectTimeout: "5" # このネットワークのみデフォルトを上書き
office:
host: 192.168.1.50
すべてのホストには default プロファイルが必要です。ネットワークプロファイルはデフォルトと異なるフィールドのみを指定すればよく、指定されていないフィールドは default から継承されます。
ホストプロファイルフィールド
| フィールド | 型 | 説明 |
|---|---|---|
host | string | ホスト名またはIPアドレス |
port | int | SSHポート(デフォルト:22) |
user | string | SSHユーザー |
key | string | IDファイルへのパス(~ は展開される) |
jump | string | ジャンプホストのエイリアスまたは user@host |
options | map | 任意のSSH -o Key=Value フラグ(例:ConnectTimeout、StrictHostKeyChecking) |
comment | string | sshroute list に表示される説明 |
tags | list | sshroute list --tag でフィルタリングするためのタグ |
options キーは default からネットワークプロファイルにマージされます。ネットワーク値は一致するキーを上書きし、重複しないキーは継承されます。
ネットワーク検出
ネットワークは priority 順(値が低いほど先)に評価されます。同点の場合はアルファベット順です。すべてのチェックが成功した最初のネットワークが使用されます。該当なしの場合は default が適用されます。
| チェックタイプ | 成功条件 | 必須フィールド |
|---|---|---|
route | サブネット/IPがカーネルルーティングテーブルに存在する | match |
interface | 名前付きインターフェースが存在し、運用上Up状態である | match |
ping | ホストがタイムアウト内にICMPエコーに応答する | host、timeout(オプション、デフォルト2s) |
exec | シェルコマンドが終了コード0で終了する | command |
1つのネットワーク定義内の複数チェックはAND論理で評価されます。すべて成功する必要があります。
例
すぐに使える設定ファイルは examples/ にあります:
| ファイル | ユースケース |
|---|---|
basic.yaml | 単一ホスト、VPN vs パブリックフォールバック |
multi-network.yaml | オフィスLAN、corp VPN、リモートVPN、パブリック |
wireguard-backconnect.yaml | あなたにバックコネクトするWireGuardピア |
jump-hosts.yaml | ネットワークごとに異なるバスティオン |
multi-zone-roaming.yaml | WireGuardゲートウェイとローミングモバイルデバイスを使用したマルチゾーンホームラボ |
ドキュメント
詳細ガイドは docs/ にあります:
| ガイド | 説明 |
|---|---|
| ホームラボセットアップ | WireGuard、ジャンプホスト、NAS、k3sノードを使ったマルチゾーンホームラボ |
| マルチゾーンローミング | 複数のLAN、WireGuardゲートウェイ、ネットワーク間をローミングするモバイルデバイス |
| 企業 / マルチ環境 | 環境別バスティオンとVPN検出によるDev/Staging/Prod |
| シャドウモード | 透過的SSH置き換え — git、rsync、scp、Ansible |
| シェル補完 | bash、zsh、fish向けの動的エイリアス補完 |
| スクリプトと自動化 | スクリプトやCIパイプラインでの resolve と copy の使用 |
出力形式
すべての一覧コマンドは複数の出力形式に対応しています:
sshroute list # table(デフォルト)
sshroute list -o json # JSON — スクリプト向け
sshroute list -o yaml # YAML
sshroute network list -o json
コミュニティ
ソフトウェア入手 — Releases からビルド済みバイナリをダウンロードするか、go install github.com/thereisnotime/sshroute@latest でインストール、またはソースからビルド。
フィードバックとバグ報告 — GitHub Issues で課題を作成してください。予期しない動作にはバグ報告テンプレート、アイデアには機能リクエストテンプレートを使用してください。
貢献 — プロジェクトのセットアップ方法、テストの実行方法、プルリクエストの開き方については CONTRIBUTING.md を参照してください。セキュリティ脆弱性は GitHub Security Advisories を介して非公開で報告してください。
ソースからのビルド
git clone [email protected]:thereisnotime/sshroute.git
cd sshroute
just build # 出力 bin/sshroute
just build-all # クロスコンパイル linux/darwin × amd64/arm64
just test # レース検出器付きテスト実行
just install # バージョンldflagsを注入して go install