
Netzwerkbewusster SSH-Router - leitet Verbindungen zu verschiedenen IPs/Ports/Keys/Sprunghosts basierend auf dem aktiven VPN oder Netzwerk um.
Netzwerkbewusster SSH-Router. Erkennt Ihr aktives Netzwerk oder VPN und wählt automatisch den richtigen Host, Port, Identity File und Jump-Host für jede SSH-Verbindung aus – ohne ~/.ssh/config anfassen zu müssen.
Definieren Sie jeden logischen Host einmal mit einem default-Profil und optionalen netzwerkspezifischen Überschreibungen. Bei jeder Verbindung erkennt sshroute, in welchem Netzwerk Sie sich befinden (VPN, Büro-LAN, WireGuard-Peer usw.) und löst die korrekten SSH-Parameter auf, bevor es an das echte /usr/bin/ssh übergibt.
ssh myserver
→ sshroute erkennt: corp-vpn ist aktiv
→ löst auf: 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
Ihr Labor hat wahrscheinlich mindestens zwei Realitäten: Entweder Sie sitzen zu Hause im LAN oder Sie sind unterwegs und kommen über WireGuard oder ein anderes VPN herein. Das Problem: ~/.ssh/config weiß nicht, in welchem Sie sich befinden – also landen Sie bei separaten Aliasen (server-lan, server-vpn), einem Jump-Host, der nur halb funktioniert, oder Sie merken sich einfach IPs.
sshroute löst dies, indem es vor jeder Verbindung Ihr aktuelles Netzwerk erkennt. Wenn das WireGuard-Interface aktiv ist und die Peer-Route existiert, verbindet es direkt zur Tunnel-IP. Wenn Sie im LAN sind, verwendet es die lokale Adresse. Wenn keines erreichbar ist, fällt es auf den öffentlichen Hostnamen zurück. Ein Alias, drei Realitäten, null manuelles Umschalten.
Außerdem fängt sshroute SSH transparent ab – git push, rsync, scp werden automatisch darüber geleitet, sobald Sie den Schattenmodus eingerichtet haben. Keine Wrapper, keine Shell-Funktionen, kein Nachdenken.
Unternehmensnetzwerke sind noch schlimmer. Sie haben das öffentliche Internet, vielleicht ein Site-to-Site-VPN, vielleicht ein persönliches VPN mit Split-Tunnel, und darin verschiedene Jump-Hosts, je nachdem, welche Umgebung Sie anvisieren – Dev, Staging, Prod, jede mit eigener Bastion und eigenem Schlüssel. Das in ~/.ssh/config gerade zu halten bedeutet entweder eine riesige Konfiguration, die bei jeder Infrastrukturänderung kaputt geht, oder ein Skript, das jedes Teammitglied anders pflegt.
sshroute ermöglicht es Ihnen, die Routinglogik deklarativ zu definieren, in einer versionierten YAML-Datei zu speichern und im Team zu teilen. Die gleiche Konfiguration funktioniert für alle – das richtige Netzwerk wird automatisch erkannt, basierend darauf, welche Interfaces oder Routen auf jedem Rechner aktiv sind. Schlüssel, Ports, Benutzer und Jump-Hosts werden aufgelöst, ohne dass der Benutzer darüber nachdenken muss.
Teleport und Boundary sind eine andere Kategorie – sie fügen Zugriffskontrolle, Audit-Logs und zertifikatsbasierte Authentifizierung zum Routing hinzu. Wenn Sie das brauchen, nutzen Sie sie. sshroute ist für diejenigen, die die Routing-Intelligenz wollen, ohne den Betriebsaufwand eines zentralen Auth-Servers.
Laden Sie die neueste Veröffentlichung von GitHub Releases herunter. Binärdateien sind für Linux, macOS und Android auf AMD64 und ARM64 verfügbar.
go install github.com/thereisnotime/sshroute@latest
Laden Sie das android_arm64-Tarball von GitHub Releases herunter, extrahieren Sie es und legen Sie die Binärdatei in ~/.local/bin ab:
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
Fügen Sie ~/.local/bin zu Ihrem PATH in ~/.bashrc oder ~/.profile hinzu, falls noch nicht geschehen:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Alternativ können Sie mit Termux' Go aus dem Quellcode kompilieren. Da die offizielle Go-Toolchain keine android/arm64-Binärdateien veröffentlicht, setzen Sie GOTOOLCHAIN=local, um die von Termux mitgelieferte Version zu verwenden:
GOTOOLCHAIN=local go install github.com/thereisnotime/sshroute@latest
Setzen Sie nach der Installation den SSH-Binärpfad, da Termux kein /usr/bin/ssh hat:
# ~/.config/sshroute/config.yaml
ssh_binary: /data/data/com.termux/files/usr/bin/ssh
Oder per Umgebungsvariable: export SSHROUTE_SSH=$(which ssh)
docker run --rm -v ~/.config/sshroute:/root/.config/sshroute \
ghcr.io/thereisnotime/sshroute network
podman run --rm -v ~/.config/sshroute:/root/.config/sshroute \
ghcr.io/thereisnotime/sshroute network
Auf Systemen mit SELinux (Fedora, RHEL usw.) fügen Sie dem Volume-Flag :Z hinzu:
podman run --rm -v ~/.config/sshroute:/root/.config/sshroute:Z \
ghcr.io/thereisnotime/sshroute network
Installieren Sie sshroute als ssh weiter vorne in Ihrem $PATH. Alle SSH-Aufrufe – vom Terminal, von git, rsync, scp – werden automatisch abgefangen. Hosts, die nicht in Ihrer Konfiguration stehen, werden unverändert an /usr/bin/ssh durchgereicht.
mkdir -p ~/.local/bin
ln -s $(which sshroute) ~/.local/bin/ssh
# In ~/.bashrc oder ~/.zshrc hinzufügen, falls nicht vorhanden:
export PATH="$HOME/.local/bin:$PATH"
# Einen Host mit einem Standardprofil hinzufügen
sshroute add myserver --host myserver.example.com --user alice --key ~/.ssh/id_ed25519
# Eine VPN-spezifische Überschreibung hinzufügen
sshroute add myserver --network vpn --host 10.8.0.50 --port 2222 --jump bastion.vpn
# Verbinden – Netzwerk wird automatisch erkannt
sshroute connect myserver
# Den aufgelösten Befehl anzeigen, ohne ihn auszuführen
sshroute connect myserver --dry-run
# Sehen, welches Netzwerk gerade aktiv ist
sshroute network
Diese Flags gelten für jeden Befehl:
initErstellt eine Startkonfigurationsdatei mit kommentierten Beispielen. Schlägt fehl, wenn die Datei bereits existiert.
| Flag | Standard | Beschreibung |
|---|---|---|
--force | false | Vorhandene Konfigurationsdatei überschreiben |
connect <alias>Erkennt das aktive Netzwerk, löst die SSH-Parameter für alias auf und führt die echte SSH-Binärdatei aus. Zusätzliche Argumente nach dem Alias werden unverändert an SSH durchgereicht.
Mit --reconnect hält sshroute die SSH-Verbindung über abgebrochene Verbindungen hinweg aufrecht (Laptop-Schlaf, WLAN-Handover, Roaming zwischen Netzwerken). Da es bei jeder Wiederverbindung das Netzwerk neu erkennt, folgt es Ihnen auf eine andere Route: Werden Sie z. B. im LAN schlafen und an einem Hotspot aufwachen, wird über die öffentliche Route neu verbunden, anstatt die jetzt unerreichbare LAN-Adresse erneut zu versuchen. Ein sauberer Logout (Exit 0) oder ein Fehler bei Authentifizierung/Remote-Befehl stoppt die Schleife; nur echte Verbindungsabbrüche lösen eine Wiederverbindung aus. Der Wiederverbindungsmodus startet ssh als Unterprozess (wie --fallback), sodass sshroute für die Sitzung resident bleibt; SIGINT/SIGTERM beendet es. Der Sitzungszustand über den Aussetzer hinweg ist Aufgabe Ihres Multiplexers (tmux/zellij); kombinieren Sie --reconnect mit -- tmux attach oder -- zellij attach -c <name>, um direkt in Ihre Sitzung zurückzukehren:
sshroute connect myserver --reconnect --fallback -- zellij attach -c work
listListet alle konfigurierten Hosts und die SSH-Parameter auf, die im aktuellen Netzwerk verwendet würden. Unterstützt -o table|json|yaml.
add <alias>Fügt einen Host hinzu oder aktualisiert einen vorhandenen. Ausgelassene Flags behalten ihren aktuellen Wert. Führen Sie den Befehl mehrmals mit verschiedenen --network-Werten aus, um netzwerkspezifische Überschreibungen zu erstellen.
remove <alias>Entfernt alle Profile für alias aus der Konfiguration.
networkGibt den Namen des aktuell erkannten Netzwerks aus (oder default, wenn keins passt).
network listListet alle konfigurierten Netzwerke mit ihrer Priorität, Prüfregeln und aktuellem Aktivitätsstatus auf. Unterstützt -o table|json|yaml.
network test <name>Führt jede Prüfung für das Netzwerk name aus und gibt bestanden/nicht bestanden pro Regel aus. Nützlich zum Debuggen der Erkennungslogik.
configGibt den aufgelösten Pfad zur Konfigurationsdatei aus.
config editÖffnet die Konfigurationsdatei in $EDITOR (fällt auf nano zurück). Erstellt die Datei und das übergeordnete Verzeichnis, falls sie nicht existieren.
resolve <alias>Gibt die SSH-Parameter aus, die für alias im aktuellen Netzwerk verwendet würden. Nützlich zum Debuggen und für Skripte. Verwenden Sie --network <name>, um das erkannte Netzwerk zu überschreiben. Unterstützt -o table|json|yaml.
| Flag | Standard | Beschreibung |
|---|---|---|
--network | automatische Erkennung | Netzwerkprofil, gegen das aufgelöst werden soll |
copy <alias> <src> <dst>Kopiert Dateien zu oder von einem konfigurierten Host mit scp unter Verwendung derselben aufgelösten Parameter (Schlüssel, Port, Jump) wie connect. Verwenden Sie die Syntax <alias>:<pfad> für entfernte Pfade:
sshroute copy myserver ./local.txt myserver:/remote/path/
sshroute copy myserver myserver:/remote/file.txt ./local/
Die Umgebungsvariable SSHROUTE_SCP überschreibt die verwendete scp-Binärdatei.
versionGibt Version, Git-Commit, Build-Datum und Go-Laufzeitinformationen aus.
updateAktualisiert sshroute direkt auf die neueste GitHub-Version. Es lädt das Archiv für Ihre Plattform herunter, überprüft dessen sha256 gegen checksums.txt und – falls cosign installiert ist – die Cosign-Signatur der Version, bevor es die laufende Binärdatei atomar ersetzt.
sshroute update # neueste Version herunterladen, verifizieren und installieren
sshroute update --check # nur melden, ob eine neuere Version verfügbar ist
sshroute update --force # neueste Version auch neu installieren, wenn bereits aktuell
Wenn die sha256-Prüfung (oder Cosign, falls vorhanden) fehlschlägt, wird das Update abgebrochen und die Binärdatei bleibt unberührt. Dieses Ziel sind Installationen der Release-Binärdatei; wenn Sie über go install oder einen Paketmanager installiert haben, aktualisieren Sie damit.
Standardpfad: ~/.config/sshroute/config.yaml
networks:
corp-vpn:
priority: 10 # niedriger = zuerst geprüft
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: # erforderlich – wird verwendet, wenn kein Netzwerk passt
host: myserver.example.com
port: 22
user: alice
key: ~/.ssh/id_ed25519
options: # optional – als SSH -o Key=Value Flags übergeben
ConnectTimeout: "10"
ServerAliveInterval: "30"
corp-vpn:
host: 10.100.0.50
port: 2222
key: ~/.ssh/corp_key
jump: bastion.corp.internal
options:
ConnectTimeout: "5" # überschreibt den Standard nur für dieses Netzwerk
office:
host: 192.168.1.50
Jeder Host muss ein default-Profil haben. Netzwerkprofile müssen nur die Felder angeben, die vom Standard abweichen – nicht gesetzte Felder erben vom default.
Die options-Schlüssel werden vom default-Profil in die Netzwerkprofile gemergt – Netzwerkeinträge überschreiben übereinstimmende Schlüssel, nicht überlappende Schlüssel werden vererbt.
Netzwerke werden in der Reihenfolge der priority ausgewertet (niedrigster Wert zuerst). Alphabetische Reihenfolge entscheidet bei Gleichstand. Das erste Netzwerk, dessen Prüfungen alle bestehen, wird verwendet; wenn keins passt, gilt default.
Mehrere Prüfungen innerhalb einer Netzwerkdefinition verwenden UND-Logik – alle müssen bestehen.
Gebrauchsfertige Konfigurationsdateien befinden sich in examples/:
Ausführliche Anleitungen finden Sie in docs/:
Alle List-Befehle unterstützen mehrere Ausgabeformate:
sshroute list # Tabelle (Standard)
sshroute list -o json # JSON – für Skripte
sshroute list -o yaml # YAML
sshroute network list -o json
Software herunterladen – Laden Sie eine vorkompilierte Binärdatei von Releases herunter, installieren Sie mit go install github.com/thereisnotime/sshroute@latest oder bauen Sie aus dem Quellcode.
Feedback und Fehlerberichte – Öffnen Sie ein Issue auf GitHub Issues. Verwenden Sie die Bug-Report-Vorlage für unerwartetes Verhalten und die Feature-Request-Vorlage für Ideen.
Mitwirken – Siehe CONTRIBUTING.md für die Einrichtung des Projekts, das Ausführen von Tests und das Öffnen eines Pull Requests. Sicherheitslücken sollten privat über GitHub Security Advisories gemeldet werden.
git clone [email protected]:thereisnotime/sshroute.git
cd sshroute
just build # Ausgabe: bin/sshroute
just build-all # Cross-Kompilierung linux/darwin × amd64/arm64
just test # Tests mit Race-Detector ausführen
just install # go install mit eingefügten Versions-ldflags
|
|
| Funktion | ~/.ssh/config | Nur WireGuard | Teleport / Boundary | sshroute |
|---|
| Erkennt Ihr aktuelles Netzwerk | ❌ | ❌ | ❌ | ✅ |
| Wählt automatisch den besten Pfad | ❌ | ❌ | ❌ | ✅ |
| Fallback bei Verbindungsfehler | ❌ | ❌ | ✅ | ✅ |
| Automatische Wiederverbindung + Neurouting bei Trennung | ❌ | ⚠️ Tunnel roamt | ⚠️ via festem Proxy | ✅ |
| Ein Befehl pro Host, von überall | ❌ | ⚠️ VPN muss aktiv sein | ✅ | ✅ |
| Konfigurationsgröße für 10 Hosts × 4 Pfade | 📄 ~600 Zeilen | 📄 ~600 Zeilen + VPN-Konfig | 📄 Server-seitige Konfig | 📄 ~60 Zeilen |
| Mobile Geräte im Roaming | ⚠️ manuelle Aliase | ⚠️ VPN erforderlich | ✅ | ✅ |
| Automatisches Chaining von Jump-Hosts | ⚠️ manuelles -J | ➖ n/a | ✅ | ✅ |
| Funktioniert mit scp / rsync / git / Ansible | ✅ | ✅ | ⚠️ teilweise | ✅ |
| Keine Server-Installation auf Zielen | ✅ | ❌ | ❌ | ✅ |
| Kein Authentifizierungsserver oder Daemon erforderlich | ✅ | ❌ | ❌ | ✅ |
| Kein Client-Agent | ✅ | ❌ | ❌ | ✅ |
| Open Source, vollständig selbst gehostet | ✅ | ✅ | ⚠️ Open-Core | ✅ |
| Flag | Umgebungsvariable | Standard | Beschreibung |
|---|
--config | SSHROUTE_CONFIG | ~/.config/sshroute/config.yaml | Pfad zur Konfigurationsdatei |
-o, --output | table | Ausgabeformat: table, json, yaml | |
-v, --verbose | SSHROUTE_VERBOSE=1 | false | Debug-Ausgabe nach stderr |
--dry-run | false | Aufgelösten SSH-Befehl ausgeben, ohne ihn auszuführen |
| Flag | Standard | Beschreibung |
|---|
--fallback | false | Jedes Profil in der Prioritätsreihenfolge versuchen und nur bei einem Verbindungsfehler (Exit 255) zum nächsten wechseln |
--reconnect | false | Verbindung überwachen und bei Trennung automatisch wieder verbinden, dabei das aktive Netzwerk neu erkennen und die Route jedes Mal neu auflösen |
--reconnect-delay | 2s | Wartezeit zwischen Wiederverbindungsversuchen, wenn --reconnect gesetzt ist |
| Flag | Standard | Beschreibung |
|---|
--host | Hostname oder IP-Adresse | |
--port | 22 | SSH-Port |
--user | SSH-Benutzername | |
--key | Pfad zur Identity-Datei (unterstützt ~) | |
--jump | Jump-Host – wird als -J an SSH übergeben | |
--network | default | Netzwerkprofil, in das die Parameter geschrieben werden |
| Feld | Typ | Beschreibung |
|---|
host | string | Hostname oder IP-Adresse |
port | int | SSH-Port (Standard: 22) |
user | string | SSH-Benutzer |
key | string | Pfad zur Identity-Datei (~ wird expandiert) |
jump | string | Jump-Host-Alias oder user@host |
options | map | Beliebige SSH -o Key=Value Flags (z.B. ConnectTimeout, StrictHostKeyChecking) |
comment | string | Beschreibung, die in sshroute list angezeigt wird |
tags | list | Tags zum Filtern mit sshroute list --tag |
| Prüftyp | Besteht, wenn | Erforderliche Felder |
|---|
route | Subnetz/IP in der Kernel-Routing-Tabelle erscheint | match |
interface | Benanntes Interface existiert und ist betriebsbereit | match |
ping | Host innerhalb des Timeouts auf ICMP-Echo antwortet | host, timeout (optional, Standard 2s) |
exec | Shell-Befehl mit Exit-Code 0 beendet | command |
| Datei | Anwendungsfall |
|---|
basic.yaml | Einzelner Host, VPN vs. öffentlicher Fallback |
multi-network.yaml | Büro-LAN, Firmen-VPN, Remote-VPN, öffentlich |
wireguard-backconnect.yaml | WireGuard-Peer, der sich zu Ihnen zurückverbindet |
jump-hosts.yaml | Verschiedene Bastionen pro Netzwerk |
multi-zone-roaming.yaml | Multi-Zonen-Homelab mit WireGuard-Gateway und mobilen Geräten im Roaming |
| Anleitung | Beschreibung |
|---|
| Homelab-Einrichtung | Multi-Zonen-Homelab mit WireGuard, Jump-Hosts, NAS, k3s-Knoten |
| Multi-Zonen-Roaming | Mehrere LANs, WireGuard-Gateway, mobile Geräte, die zwischen Netzwerken roamieren |
| Unternehmen / Multi-Umgebung | Dev/Staging/Prod mit umgebungsspezifischen Bastionen und VPN-Erkennung |
| Schattenmodus | Transparenter SSH-Ersatz – git, rsync, scp, Ansible |
| Shell-Vervollständigung | Dynamische Alias-Vervollständigung für bash, zsh, fish |
| Skripterstellung und Automatisierung | Verwendung von resolve und copy in Skripten und CI-Pipelines |