SSH Tunneling
Tabularis includes a full SSH tunneling implementation written in Rust. It supports both password and key-based authentication, multi-hop proxy chains, and automatic dynamic port assignment. No external tools are required — everything runs inside the application process.
How It Works
When a database connection has SSH enabled, Tabularis:
- Opens an SSH session to the bastion host.
- Requests the OS for a free ephemeral port on
127.0.0.1. - Forwards traffic from
127.0.0.1:<local_port>through the SSH tunnel to<remote_db_host>:<remote_db_port>. - Points the database driver at
127.0.0.1:<local_port>instead of the remote host.
You never need to choose a local port — Tabularis handles it automatically.
Two Backends
Tabularis selects the SSH backend automatically based on your authentication method.
Russh (Native Rust SSH)
Used when a password is provided. The tunnel runs entirely within the Rust process — no external ssh binary is needed.
- Host key verification via
~/.ssh/known_hosts. - Trust-on-first-use for unknown hosts (the key is saved automatically).
- Hard failure if the host key has changed (possible MITM attack).
- 30-second authentication timeout.
System SSH
Used when no password is provided (key-only authentication). Tabularis spawns your system's ssh binary, which means:
- Full
~/.ssh/configsupport —ProxyJump,IdentityFile,Hostaliases, and every other directive. - Agent forwarding works if configured in your SSH config.
BatchMode=yesis set so the process never hangs waiting for interactive input.StrictHostKeyChecking=accept-new— new hosts are accepted, changed keys are rejected.
SSH Profiles
SSH connections are stored as reusable profiles in ssh_connections.json, separate from database connections. A single SSH profile (e.g., your production bastion) can be reused across multiple database connections.
Manage profiles from Settings → SSH Connections or the SSH Connections modal.
Profile Fields
| Field | Description |
|---|---|
| Name | Display label |
| Host | Bastion hostname or IP |
| Port | Default 22 |
| Username | Your user on the bastion |
| Auth type | password or ssh_key |
| Password | SSH password (triggers Russh backend) |
| Key file | Path to private key (triggers System SSH backend when no password) |
| Key passphrase | Stored in OS keychain if "Save in keychain" is checked |
Testing a Profile
Click Test before saving. Tabularis performs a real SSH handshake and reports success or the exact error message. The test uses the same backend that the connection will use.
Linking SSH to a Database Connection
- Open the connection editor (new or existing connection).
- Check SSH enabled.
- Select an SSH profile from the dropdown.
- Save the connection.
When you connect, the tunnel is established first, then the database driver connects through it. If the tunnel fails, the exact SSH error is surfaced — no generic "connection refused" messages.
Multi-Hop / ProxyJump
For databases behind multiple bastion layers, define the chain in ~/.ssh/config and use the System SSH backend (key-only auth, no password):
Host bastion
HostName bastion.example.com
User ec2-user
IdentityFile ~/.ssh/prod.pem
Host db-host
HostName 10.0.1.50
User ubuntu
ProxyJump bastion
Set the SSH profile host to db-host, auth type to ssh_key, and leave the password empty. Tabularis delegates to ssh, which resolves the chain automatically.
Tunnel Lifecycle
- Tunnels are created when you connect and destroyed when you disconnect.
- Each connection gets its own tunnel — there is no sharing between connections, even if they use the same SSH profile.
- If the tunnel drops (network interruption), the database connection will fail on the next query. Disconnect and reconnect to re-establish the tunnel.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| "Host key verification failed" | Server key changed | ssh-keygen -R <host> then reconnect |
| "Permission denied (publickey)" | Wrong key or permissions | Check key path, chmod 600 the key file |
| Tunnel up but queries time out | DB unreachable from bastion | SSH into bastion, test nc -zv <db_host> <db_port> |
| "Connection refused" on local port | Tunnel failed silently | Check SSH logs, verify bastion is reachable |
For more details, see Troubleshooting & FAQ.
