SSH tunnels to remote server.
Clone or download
tkhyn and fernandezcuesta fix(ssh): add provided ssh_pkey at the beginning of ssh_loaded_pkeys (#…

appending it at the end prevents it from being loaded first and may prompt for a password if any key in ~/.ssh requires one
Latest commit 66a923e Aug 24, 2018


CircleCI AppVeyor Documentation Status coveralls version

pyversions license

Author: Pahaz Blinov


Inspired by, but it doesn't work on Windows.

See also:



sshtunnel is on PyPI, so simply run:

pip install sshtunnel


easy_install sshtunnel


conda install -c conda-forge sshtunnel

to have it installed in your environment.

For installing from source, clone the repo and run:

python install

Testing the package

In order to run the tests you first need tox and run:

python test

Usage scenarios

One of the typical scenarios where sshtunnel is helpful is depicted in the figure below. User may need to connect a port of a remote server (i.e. 8080) where only SSH port (usually port 22) is reachable.


-------------+              |    +----------+
    LOCAL    |              |    |  REMOTE  | :22 SSH
    CLIENT   | <== SSH ========> |  SERVER  | :8080 web service
-------------+              |    +----------+
                         FIREWALL (only port 22 is open)


Fig1: How to connect to a service blocked by a firewall through SSH tunnel.

If allowed by the SSH server, it is also possible to reach a private server (from the perspective of REMOTE SERVER) not directly visible from the outside (LOCAL CLIENT's perspective).


-------------+              |    +----------+               +---------
    LOCAL    |              |    |  REMOTE  |               | PRIVATE
    CLIENT   | <== SSH ========> |  SERVER  | <== local ==> | SERVER
-------------+              |    +----------+               +---------
                         FIREWALL (only port 443 is open)


Fig2: How to connect to PRIVATE SERVER through SSH tunnel.

Usage examples

API allows either initializing the tunnel and starting it or using a with context, which will take care of starting and stopping the tunnel:

Example 1

Code corresponding to Fig1 above follows, given remote server's address is, password authentication and randomly assigned local bind port.

from sshtunnel import SSHTunnelForwarder

server = SSHTunnelForwarder(
    remote_bind_address=('', 8080)


print(server.local_bind_port)  # show assigned local port
# work with `SECRET SERVICE` through `server.local_bind_port`.


Example 2

Example of a port forwarding to a private server not directly reachable, assuming password protected pkey authentication, remote server's SSH service is listening on port 443 and that port is open in the firewall (Fig2):

import paramiko
from sshtunnel import SSHTunnelForwarder

with SSHTunnelForwarder(
    (REMOTE_SERVER_IP, 443),
    remote_bind_address=(PRIVATE_SERVER_IP, 22),
    local_bind_address=('', 10022)
) as tunnel:
    client = paramiko.SSHClient()
    client.connect('', 10022)
    # do some operations with client session


Example 3

Example of a port forwarding for the Vagrant MySQL local port:

from sshtunnel import SSHTunnelForwarder
from time import sleep

with SSHTunnelForwarder(
    ('localhost', 2222),
    remote_bind_address=('', 3306)
) as server:

    while True:
        # press Ctrl-C for stopping


Or simply using the CLI:

(bash)$ python -m sshtunnel -U vagrant -P vagrant -L :3306 -R -p 2222 localhost

CLI usage

$ sshtunnel --help
usage: sshtunnel [-h] [-U SSH_USERNAME] [-p SSH_PORT] [-P SSH_PASSWORD] -R
                 IP:PORT [IP:PORT ...] [-L [IP:PORT [IP:PORT ...]]]
                 [-k SSH_HOST_KEY] [-K KEY_FILE] [-S KEY_PASSWORD] [-t] [-v]
                 [-V] [-x IP:PORT] [-c SSH_CONFIG_FILE] [-z] [-n] [-d [FOLDER [FOLDER ...]]]

Pure python ssh tunnel utils
Version 0.1.4

positional arguments:
  ssh_address           SSH server IP address (GW for SSH tunnels)
                        set with "-- ssh_address" if immediately after -R or -L

optional arguments:
  -h, --help            show this help message and exit
                        SSH server account username
  -p SSH_PORT, --server_port SSH_PORT
                        SSH server TCP port (default: 22)
                        SSH server account password
  -R IP:PORT [IP:PORT ...], --remote_bind_address IP:PORT [IP:PORT ...]
                        Remote bind address sequence: ip_1:port_1 ip_2:port_2 ... ip_n:port_n
                        Equivalent to ssh -Lxxxx:IP_ADDRESS:PORT
                        If port is omitted, defaults to 22.
                        Example: -R
  -L [IP:PORT [IP:PORT ...]], --local_bind_address [IP:PORT [IP:PORT ...]]
                        Local bind address sequence: ip_1:port_1 ip_2:port_2 ... ip_n:port_n
                        Elements may also be valid UNIX socket domains:
                        /tmp/foo.sock /tmp/bar.sock ... /tmp/baz.sock
                        Equivalent to ssh -LPORT:xxxxxxxxx:xxxx, being the local IP address optional.
                        By default it will listen in all interfaces ( and choose a random port.
                        Example: -L :40000
  -k SSH_HOST_KEY, --ssh_host_key SSH_HOST_KEY
                        Gateway's host key
  -K KEY_FILE, --private_key_file KEY_FILE
                        RSA/DSS/ECDSA private key file
  -S KEY_PASSWORD, --private_key_password KEY_PASSWORD
                        RSA/DSS/ECDSA private key password
  -t, --threaded        Allow concurrent connections to each tunnel
  -v, --verbose         Increase output verbosity (default: ERROR)
  -V, --version         Show version number and quit
  -x IP:PORT, --proxy IP:PORT
                        IP and port of SSH proxy to destination
                        SSH configuration file, defaults to ~/.ssh/config
  -z, --compress        Request server for compression over SSH transport
  -n, --noagent         Disable looking for keys from an SSH agent
  -d [FOLDER [FOLDER ...]], --host_pkey_directories [FOLDER [FOLDER ...]]
                        List of directories where SSH pkeys (in the format `id_*`) may be found