For one of my projects, I have a web application running on one machine and a
separate reporting application on another machine that must connect to the
database (PostgreSQL) on the first. By default, PostgreSQL listens only on
In order to connect the reporting application, which was a later addition to the project, to the PostgreSQL database without restarting it to load an updated configuration, I established an SSH tunnel between the reporting server and the application server. I didn’t want the tunnel open all the time, so I moved the tunnel creation inside my reporting application.
In this post, I will cover how to use JSch, or ‘Java Secure Channel’, a Java implementation of the SSH protocol, to set up SSH port forwarding inside a Java application.
In the setup below, I will refer to two servers:
app, where the application
and database server are running, and
report, where the reporting application
is running. Both servers have a
reporting user account.
report, I created an SSH key pair (with no passphrase) for
reporting. This is stored in
/home/reporting/.ssh/id_rsa. I copied the public key (
known_hosts file on
I tested the connection using
report in order to populate the
Making the Connection in Java
JSch is available in the central Maven repository.
I added it to my reporting application’s
In the application, I establish the SSH tunnel as follows. Import the Jsch classes:
At some point before attempting to establish a database connection, create the tunnel:
From top to bottom:
addIdentitytakes the path of the private key whose public counterpart is on the server you’re connecting to.
setKnownHoststakes the path of your
known_hostsfile which needs to have the fingerprint of the server you’re connecting to already
getSessiontakes three parameters: the username on the server you’re connecting to, the hostname to connect to, and the SSH port
setPortForwardingLtakes three parameters: the local port for local port forwarding, the host address, and the remote port (but see below)
The second string parameter to
setPortForwardingL in the example code given by the
JSch website is the remote host (i.e.,
app, here). This overload of the method calls
another overload which sets the bind address to
127.0.0.1 (see here).
This would be consistent with the command-line options for
However, setting the second parameter to the remote host does not work for me. After
establishing the session with
getSession, I’ve only been able to successfully enable
local port forwarding by passing
localhost as the second parameter.
At this point, connecting to
localhost on port
1111 will connect to the tunnel
app with an endpoint of
5432 (PostgreSQL). For example, if you’re using JDBC,
you could use a connection string like
After you’re done with the tunnel, don’t forget to clean up: