Reaching a database behind an SSH bastion is a common use case for any developer who works with production servers. Most database clients embed an SSH library (libssh2, russh, paramiko) to handle this network layer internally. QoreDB makes a different choice: fully delegating the tunnel to the OpenSSH client installed on the user's machine.
This choice has direct consequences on compatibility, security and code maintenance. Here's how it works in practice.
Why delegate to the OpenSSH client
Embedding an SSH library in a desktop client raises several concrete problems. You have to track the library's CVEs, manage updates independently of the system, and reproduce behavior the OS already handles very well. The OpenSSH client is installed by default on macOS, Linux, and Windows 10+ (via the optional OpenSSH component). It is actively maintained, regularly audited, and natively supports SSH agents, configuration files, and the most recent protocols.
By delegating to the system binary, QoreDB automatically inherits the user's entire SSH configuration: the keys loaded in ssh-agent, the entries in the ~/.ssh/config file, the algorithms negotiated by the system. There is no gap between what works in the terminal and what works in QoreDB.
The tunnel architecture in the Rust code
QoreDB's SSH module is built around two Rust traits: SshTunnelBackend and SshTunnelHandle. The first defines the interface for opening a tunnel, the second manages its lifecycle (local port, shutdown). This abstraction makes it possible to add other backends in the future without modifying the rest of the code.
Today, the only backend implemented is OpenSshBackend. It works by launching an ssh -N -L process through tokio, in non-interactive mode. The command is built with strict options: BatchMode=yes to avoid any prompt, ExitOnForwardFailure=yes to bring down the tunnel if port forwarding fails, and IdentitiesOnly=yes to try only the specified key.
Local port allocation is automatic: QoreDB opens a TCP listener on port 0, retrieves the port assigned by the OS, closes the listener, then passes that port to the SSH command. This avoids port conflicts and works with no user configuration.
Host key handling and security
Host key verification is a critical point for any SSH tunnel. QoreDB exposes three policies to the user: accept-new (TOFU, trust on first connection), strict (the key must already be in the known_hosts file), and a disabled option reserved for development.
An important point: QoreDB uses its own known_hosts file, separate from the system's. On Linux and macOS, it is stored in ~/.qoredb/ssh/known_hosts, on Windows in %APPDATA%\QoreDB\ssh\known_hosts. The system's global known_hosts file is explicitly ignored (redirected to /dev/null). This isolation guarantees deterministic behavior: server fingerprints validated through QoreDB don't interfere with those of the terminal, and vice versa.
The SSH process's stderr output is also filtered before being surfaced to the user. Internal IP addresses are anonymized, the output is truncated to 200 characters, and lines that contain identity information are removed except for "Permission denied"-type messages. This avoids leaking infrastructure details into the interface.
Bastion and ProxyJump support
In many production environments, the database isn't directly accessible. You have to go through an intermediate server (bastion or jump host). QoreDB natively supports this configuration through OpenSSH's -J option (ProxyJump). The user enters an address in the user@host:port format in the interface, and QoreDB adds it to the SSH command.
The ProxyJump field is validated on the backend with a strict regex. Special characters, spaces and injected SSH options are rejected. This is a necessary precaution because the value is passed as a command-line argument: without validation, a malicious user or a corrupted import could try to inject arbitrary SSH options.
Keep-alive and automatic reconnection
An SSH tunnel can drop silently, particularly in case of a network outage or a server-side timeout. QoreDB configures keep-alive directly in the SSH command via ServerAliveInterval and ServerAliveCountMax. By default, the client sends a signal every 30 seconds and tolerates 3 consecutive failures before dropping the connection.
On the session manager side, QoreDB also monitors the tunnel's state by periodically trying to connect to the local port. If the port stops responding, the session manager attempts to recreate the tunnel automatically with the same configuration, then to reconnect the database driver. The user doesn't need to intervene manually in most cases.
In practice: connecting to PostgreSQL through a bastion
The user experience is straightforward. In the connection form, you enable the SSH tunnel, enter the SSH server's host and port, the username, and the path to the private key. The "database host" field corresponds to the address of the database as it is reachable from the SSH server, not from the local machine. This is a point that can be surprising but is perfectly logical: with an SSH tunnel, address resolution happens on the remote server side.
At connection time, QoreDB allocates a random local port, launches the SSH process, waits for the tunnel to be operational (by probing the port every 50ms, with a 5-second timeout), then connects the database driver to 127.0.0.1:local_port. If the SSH process fails to start, the stderr error is surfaced immediately in the interface.
Delegating the SSH tunnel to the system binary is a design choice that aligns QoreDB with the existing ecosystem rather than replacing it. The user keeps their habits (ssh-agent, configuration files, OS updates), and QoreDB focuses on what it does best: providing a fast interface to explore and manipulate data. The Rust code that orchestrates this mechanism fits in a module of a few hundred lines, with an extensible trait to add other backends should the need arise.
Stay updated on new releases
Subscribe to get product releases, new drivers notifications, and technical tutorials.

