sshtunnel

Pure Python library for opening SSH tunnels and forwarding ports through a remote gateway.

Library
PyPI
v0.4.0
1,295stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
46/100Fair
Development Activity0
Maintenance20
Community76
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
71/100Good
Architecture72
Code Quality78
Innovation65
Learning Curve70

sshtunnel wraps Paramiko to make SSH port forwarding a first-class Python API rather than something you shell out to. Its SSHTunnelForwarder class spins up a background thread pool that accepts local connections and relays traffic through an SSH transport to one or more remote bind addresses, so a script can reach a database or internal service that’s only reachable through a jump host.

It supports both local-to-remote and remote-to-local forwarding, multiple simultaneous tunnels from a single SSH connection, password/key/agent authentication, reading proxy directives from ~/.ssh/config, and a context-manager style (with sshtunnel.open_tunnel(...) as tunnel:) that guarantees the tunnel is torn down cleanly. A python -m sshtunnel CLI is also bundled for ad-hoc tunnels from the shell.

What You Get

  • SSHTunnelForwarder class and open_tunnel() context-manager helper for programmatic tunnel setup and teardown
  • Local-to-remote and remote-to-local port forwarding, including multiple simultaneous bind pairs on one SSH connection
  • Password, private-key (RSA/DSS/ECDSA, encrypted or plain), and SSH-agent authentication, plus optional ~/.ssh/config parsing
  • Proxy/jump-host support via ssh_proxy (chaining tunnels or a paramiko.ProxyCommand)
  • A sshtunnel CLI entry point for opening tunnels directly from the shell without writing Python
  • Configurable logging (including a TRACE level) for debugging tunnel and channel activity

Common Use Cases

  • Connecting a local script or ORM to a remote database (Postgres, MySQL) that only accepts connections from localhost on the database server
  • Reaching internal services behind a bastion/jump host in CI pipelines or data pipelines without shelling out to ssh -L
  • Debugging or administering infrastructure where the only exposed port is SSH (port 22 or a nonstandard SSH port)
  • Building test fixtures that need a real SSH tunnel (e.g. pytest fixtures that stand up and tear down a tunnel per test)

Under The Hood

Architecture - The module is organized around a socketserver-based listener chain: _ForwardServer/_ThreadingForwardServer (TCP) and _StreamForwardServer/_ThreadingStreamForwardServer (Unix domain sockets) accept local connections and hand each one to a _ForwardHandler, whose _redirect() method uses select() to pump bytes bidirectionally between the local socket and an SSH channel opened via paramiko.Transport.open_channel(kind='direct-tcpip'). The SSHTunnelForwarder class is the orchestration layer: it owns the Paramiko Transport, spins up one listener thread per local/remote bind pair, and exposes start()/stop() plus context-manager semantics through the module-level open_tunnel() helper. Tech Stack - Pure Python (no C extensions) with a single runtime dependency, paramiko>=2.7.2, for the SSH transport and crypto; the codebase still carries Python 2/3 compatibility shims (sys.version_info branches for queue/socketserver imports) despite modern classifiers, and ships as a single sshtunnel.py module rather than a package. Code Quality - tests/test_forwarder.py is a substantial 1400-line suite (30+ unittest.TestCase tests) that spins up a real in-process Paramiko ServerInterface (NullServer) and exercises authentication paths, proxy chaining, local/remote bind variations, error conditions (unreachable gateway, bad config, missing keys), and CLI behavior end-to-end rather than mocking the transport; docstrings are extensive throughout SSHTunnelForwarder, though some exception handlers are broad except Exception blocks marked # pragma: no cover. API Design - the constructor accepts a large, well-documented set of keyword arguments (30+) with explicit deprecation shims (e.g. ssh_address -> ssh_address_or_host) that emit warnings rather than breaking callers, and open_tunnel()’s context-manager form keeps the common case to a few lines; the tradeoff is a wide, somewhat overloaded single-class surface rather than smaller composable pieces.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search