
sshroute v0.2.11
Roteador SSH consciente da rede - roteia conexões para diferentes IPs/portas/chaves/hosts de salto com base na VPN ou rede ativa
sshroute
Roteador SSH ciente de rede. Detecta sua rede ativa ou VPN e seleciona automaticamente o host, porta, arquivo de identidade e host de salto corretos para cada conexão SSH — sem tocar no ~/.ssh/config.
Como funciona
Defina cada host lógico uma vez com um perfil default e substituições opcionais por rede. Em cada conexão, o sshroute detecta em qual rede você está (VPN, LAN do escritório, peer WireGuard, etc.) e resolve os parâmetros SSH corretos antes de passar para o /usr/bin/ssh real.
ssh myserver
→ sshroute detecta: corp-vpn está ativo
→ resolve: 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
Por que sshroute?
Para donos de homelab
Seu laboratório provavelmente tem pelo menos duas realidades: você está em casa na LAN, ou está fora e acessa via WireGuard ou outra VPN. O problema é que o ~/.ssh/config não sabe em qual você está — então você acaba com apelidos separados (server-lan, server-vpn), ou um host de salto que só funciona metade do tempo, ou você simplesmente memoriza IPs.
O sshroute resolve isso detectando sua rede atual antes de cada conexão. Quando a interface WireGuard está ativa e a rota do peer existe, ele conecta diretamente ao IP do túnel. Quando você está na LAN, ele usa o endereço local. Quando nenhum é alcançável, ele recai para o nome de host público. Um apelido, três realidades, zero troca manual.
Ele também intercepta SSH de forma transparente — git push, rsync, scp passam automaticamente por ele assim que você configura o modo sombra. Sem wrappers, sem funções de shell, sem pensar.
Para ambientes corporativos
Redes empresariais são piores. Você tem a internet pública, talvez uma VPN site-to-site, talvez uma VPN pessoal com split-tunnel, e dentro disso você tem diferentes hosts de salto dependendo de qual ambiente está mirando — dev, staging, produção, cada um com seu bastião e chave. Manter isso correto no ~/.ssh/config significa ou um arquivo enorme que quebra quando a infra muda, ou você escreve um script que cada pessoa da equipe mantém de forma diferente.
O sshroute permite que você defina a lógica de roteamento de forma declarativa, mantenha-a em um arquivo YAML versionado e compartilhe com a equipe. A mesma configuração funciona para todos — a rede correta é detectada automaticamente com base em quais interfaces ou rotas estão ativas em cada máquina. Chaves, portas, usuários e hosts de salto são resolvidos sem que o usuário precise pensar nisso.
Como se compara
| Funcionalidade | ~/.ssh/config | Somente WireGuard | Teleport / Boundary | sshroute |
|---|---|---|---|---|
| Detecta sua rede atual | ❌ | ❌ | ❌ | ✅ |
| Escolhe o melhor caminho automaticamente | ❌ | ❌ | ❌ | ✅ |
| Recai em caso de falha de conexão | ❌ | ❌ | ✅ | ✅ |
| Reconexão automática + re-roteamento ao cair | ❌ | ⚠️ túnel faz roaming | ⚠️ via proxy fixo | ✅ |
| Um comando por host, qualquer local | ❌ | ⚠️ VPN precisa estar ativa | ✅ | ✅ |
| Tamanho da config para 10 hosts × 4 caminhos | 📄 ~600 linhas | 📄 ~600 linhas + config VPN | 📄 config no servidor | 📄 ~60 linhas |
| Dispositivos móveis em roaming | ⚠️ apelidos manuais | ⚠️ VPN necessária | ✅ | ✅ |
| Encadeamento automático de host de salto | ⚠️ -J manual | ➖ n/a | ✅ | ✅ |
| Funciona com scp / rsync / git / Ansible | ✅ | ✅ | ⚠️ parcial | ✅ |
| Sem instalação no servidor nos alvos | ✅ | ❌ | ❌ | ✅ |
| Sem servidor de autenticação ou daemon para executar | ✅ | ❌ | ❌ | ✅ |
| Sem agente cliente | ✅ | ❌ | ❌ | ✅ |
| Código aberto, totalmente auto-hospedado | ✅ | ✅ | ⚠️ open-core | ✅ |
Teleport e Boundary são uma categoria diferente — eles adicionam controle de acesso, logs de auditoria e autenticação baseada em certificado sobre o roteamento. Se é isso que você precisa, use-os. O sshroute é para quando você quer a inteligência de roteamento sem a sobrecarga operacional de executar um servidor de autenticação central.
Instalação
Download do binário
Baixe a versão mais recente em GitHub Releases. Binários estão disponíveis para Linux, macOS e Android em AMD64 e ARM64.
Instalação via Go
go install github.com/thereisnotime/sshroute@latest
Android (Termux)
Baixe o pacote android_arm64 do GitHub Releases, extraia e coloque o binário em ~/.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
Adicione ~/.local/bin ao seu PATH no ~/.bashrc ou ~/.profile se ainda não estiver:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Alternativamente, compile a partir do código-fonte com o Go do Termux. Como a toolchain oficial do Go não publica binários android/arm64, defina GOTOOLCHAIN=local para usar o que o Termux fornece:
GOTOOLCHAIN=local go install github.com/thereisnotime/sshroute@latest
Após instalar, defina o caminho do binário SSH, já que o Termux não tem /usr/bin/ssh:
# ~/.config/sshroute/config.yaml
ssh_binary: /data/data/com.termux/files/usr/bin/ssh
Ou via variável de ambiente: 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
Em sistemas com SELinux ativado (Fedora, RHEL, etc.) adicione :Z ao flag de volume:
podman run --rm -v ~/.config/sshroute:/root/.config/sshroute:Z \
ghcr.io/thereisnotime/sshroute network
Modo sombra (substituto transparente do SSH)
Instale o sshroute como ssh antes no seu $PATH. Todas as chamadas SSH — do seu terminal, git, rsync, scp — são interceptadas automaticamente. Hosts que não estão na sua configuração passam para o /usr/bin/ssh sem alterações.
mkdir -p ~/.local/bin
ln -s $(which sshroute) ~/.local/bin/ssh
# Adicione ao ~/.bashrc ou ~/.zshrc se ainda não estiver:
export PATH="$HOME/.local/bin:$PATH"
Início rápido
# Adicione um host com um perfil padrão
sshroute add myserver --host myserver.example.com --user alice --key ~/.ssh/id_ed25519
# Adicione uma substituição específica para VPN
sshroute add myserver --network vpn --host 10.8.0.50 --port 2222 --jump bastion.vpn
# Conecte — a rede é detectada automaticamente
sshroute connect myserver
# Visualize o comando resolvido sem executá-lo
sshroute connect myserver --dry-run
# Veja qual rede está ativa no momento
sshroute network
Comandos
Flags globais
Estas flags se aplicam a todos os comandos:
| Flag | Variável de ambiente | Padrão | Descrição |
|---|---|---|---|
--config | SSHROUTE_CONFIG | ~/.config/sshroute/config.yaml | Caminho do arquivo de configuração |
-o, --output | table | Formato de saída: table, json, yaml | |
-v, --verbose | SSHROUTE_VERBOSE=1 | false | Log de depuração no stderr |
--dry-run | false | Imprime o comando SSH resolvido sem executar |
init
Cria um arquivo de configuração inicial com exemplos comentados. Falha se o arquivo já existir.
| Flag | Padrão | Descrição |
|---|---|---|
--force | false | Sobrescreve um arquivo de configuração existente |
connect <alias>
Detecta a rede ativa, resolve os parâmetros SSH para alias e executa o binário SSH real. Quaisquer argumentos extras após o alias são passados diretamente para o SSH sem alteração.
| Flag | Padrão | Descrição |
|---|---|---|
--fallback | false | Tenta cada perfil em ordem de prioridade, repetindo o próximo apenas em caso de falha de conexão (código de saída 255) |
--reconnect | false | Supervisiona a conexão e reconecta automaticamente quando ela cai, redetectando a rede ativa e re-resolvendo a rota a cada vez |
--reconnect-delay | 2s | Tempo de espera entre tentativas de reconexão quando --reconnect está definido |
Com --reconnect, o sshroute mantém o ssh ativo durante quedas de conexão (suspensão do laptop, handoff de WiFi, roaming entre redes). Como ele redetecta a rede a cada reconexão, ele te segue para uma rota diferente: por exemplo, dormir na LAN e acordar em um hotspot reconecta pela rota pública em vez de tentar novamente o endereço LAN agora inalcançável. Um logout limpo (código 0) ou uma falha de autenticação/comando remoto interrompe o loop; apenas quedas genuínas de conexão reconectam. O reconnect executa o ssh como subprocesso (como --fallback), então o sshroute permanece residente durante a sessão; SIGINT/SIGTERM o derruba. O estado da sessão durante o lapso é responsabilidade do seu multiplexador (tmux/zellij); combine --reconnect com -- tmux attach ou -- zellij attach -c <name> para cair direto na sua sessão:
sshroute connect myserver --reconnect --fallback -- zellij attach -c work
list
Lista todos os hosts configurados e os parâmetros SSH que seriam usados na rede atual. Suporta -o table|json|yaml.
add <alias>
Adiciona um host ou atualiza um existente. Flags omitidas mantêm seu valor atual. Execute várias vezes com diferentes valores de --network para construir substituições por rede.
| Flag | Padrão | Descrição |
|---|---|---|
--host | Nome do host ou endereço IP | |
--port | 22 | Porta SSH |
--user | Usuário SSH | |
--key | Caminho para o arquivo de identidade (suporta ~) | |
--jump | Host de salto — passado como -J para o SSH | |
--network | default | Perfil de rede no qual escrever os parâmetros |
remove <alias>
Remove todos os perfis de alias da configuração.
network
Imprime o nome da rede atualmente detectada (ou default se nenhuma corresponder).
network list
Lista todas as redes configuradas com sua prioridade, regras de verificação e estado ativo atual. Suporta -o table|json|yaml.
network test <name>
Executa cada verificação para a rede name e imprime passou/falhou por regra. Útil para depurar a lógica de detecção.
config
Imprime o caminho resolvido para o arquivo de configuração.
config edit
Abre o arquivo de configuração no $EDITOR (recai para nano). Cria o arquivo e seu diretório pai se não existirem.
resolve <alias>
Imprime os parâmetros SSH que seriam usados para alias na rede atual. Útil para depuração e scripts. Use --network <name> para sobrescrever a rede detectada. Suporta -o table|json|yaml.
| Flag | Padrão | Descrição |
|---|---|---|
--network | detecção automática | Perfil de rede contra o qual resolver |
copy <alias> <src> <dst>
Copia arquivos de ou para um host configurado usando scp com os mesmos parâmetros resolvidos (chave, porta, salto) que connect. Use a sintaxe <alias>:<path> para caminhos remotos:
sshroute copy myserver ./local.txt myserver:/remote/path/
sshroute copy myserver myserver:/remote/file.txt ./local/
A variável de ambiente SSHROUTE_SCP substitui o binário scp usado.
version
Imprime a versão, commit git, data de compilação e informações do runtime Go.
update
Atualiza o sshroute no local para o último lançamento do GitHub. Ele baixa o arquivo para sua plataforma, verifica seu sha256 em relação ao checksums.txt e — se o cosign estiver instalado — verifica a assinatura cosign do lançamento, antes de substituir atomicamente o binário em execução.
sshroute update # baixa, verifica e instala o último lançamento
sshroute update --check # apenas informa se uma versão mais nova está disponível
sshroute update --force # reinstala o último mesmo se já estiver atualizado
Se a verificação sha256 (ou cosign, quando presente) falhar, a atualização é abortada e o binário permanece intacto. Isso tem como alvo instalações do binário de lançamento; se você instalou via go install ou um gerenciador de pacotes, atualize por esses meios.
Arquivo de configuração
Localização padrão: ~/.config/sshroute/config.yaml
networks:
corp-vpn:
priority: 10 # menor = verificado primeiro
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: # obrigatório — usado quando nenhuma rede corresponde
host: myserver.example.com
port: 22
user: alice
key: ~/.ssh/id_ed25519
options: # opcional — passado como flags 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" # substitui o padrão apenas para esta rede
office:
host: 192.168.1.50
Todo host deve ter um perfil default. Perfis de rede só precisam especificar campos que diferem do padrão — campos não definidos herdam do default.
Campos do perfil do host
| Campo | Tipo | Descrição |
|---|---|---|
host | string | Nome do host ou endereço IP |
port | int | Porta SSH (padrão: 22) |
user | string | Usuário SSH |
key | string | Caminho para o arquivo de identidade (~ é expandido) |
jump | string | Apelido do host de salto ou user@host |
options | mapa | Flags SSH -o Key=Value arbitrários (ex.: ConnectTimeout, StrictHostKeyChecking) |
comment | string | Descrição mostrada em sshroute list |
tags | lista | Tags para filtragem com sshroute list --tag |
As chaves de options são mescladas de default para perfis de rede — valores de rede substituem chaves correspondentes, chaves não sobrepostas são herdadas.
Detecção de rede
As redes são avaliadas em ordem de priority (menor valor primeiro). Ordem alfabética desempata. A primeira rede cujas verificações passam é usada; se nenhuma corresponder, default se aplica.
| Tipo de verificação | Passa quando | Campos obrigatórios |
|---|---|---|
route | Sub-rede/IP aparece na tabela de roteamento do kernel | match |
interface | Interface nomeada existe e está operacionalmente ativa | match |
ping | O host responde ao eco ICMP dentro do tempo limite | host, timeout (opcional, padrão 2s) |
exec | O comando shell sai com código 0 | command |
Múltiplas verificações dentro de uma definição de rede usam lógica E — todas devem passar.
Exemplos
Arquivos de configuração prontos para uso estão em examples/:
| Arquivo | Caso de uso |
|---|---|
basic.yaml | Host único, recuo entre VPN e público |
multi-network.yaml | LAN do escritório, VPN corporativa, VPN remota, público |
wireguard-backconnect.yaml | Peer WireGuard que se reconecta a você |
jump-hosts.yaml | Bastiões diferentes por rede |
multi-zone-roaming.yaml | Homelab multi-zona com gateway WireGuard e dispositivos móveis em roaming |
Documentação
Guias aprofundados estão em docs/:
| Guia | Descrição |
|---|---|
| Configuração de homelab | Homelab multi-zona com WireGuard, hosts de salto, NAS, nós k3s |
| Roaming multi-zona | Várias LANs, gateway WireGuard, dispositivos móveis que roam entre redes |
| Ambiente corporativo / multi-ambiente | Dev/staging/prod com bastiões por ambiente e detecção de VPN |
| Modo sombra | Substituto transparente do SSH — git, rsync, scp, Ansible |
| Complemento de shell | Complemento dinâmico de apelidos para bash, zsh, fish |
| Scripts e automação | Usando resolve e copy em scripts e pipelines CI |
Formatos de saída
Todos os comandos de listagem suportam múltiplos formatos de saída:
sshroute list # table (padrão)
sshroute list -o json # JSON — para scripts
sshroute list -o yaml # YAML
sshroute network list -o json
Comunidade
Obtenha o software — baixe um binário pré-compilado de Releases, instale com go install github.com/thereisnotime/sshroute@latest, ou compile a partir do código-fonte.
Feedback e relatórios de bug — abra uma issue em GitHub Issues. Use o modelo de relatório de bug para comportamento inesperado e o modelo de solicitação de funcionalidade para ideias.
Contribuições — veja CONTRIBUTING.md para saber como configurar o projeto, executar testes e abrir um pull request. Vulnerabilidades de segurança devem ser relatadas em particular via GitHub Security Advisories.
Compilando a partir do código-fonte
git clone [email protected]:thereisnotime/sshroute.git
cd sshroute
just build # gera bin/sshroute
just build-all # compilação cruzada linux/darwin × amd64/arm64
just test # executa testes com detector de raça
just install # go install com ldflags de versão injetadas