Heroku Exec (SSH Tunneling)

Heroku Exec is a feature for creating secure TCP and SSH tunnels into a dyno. It allows for SSH sessions, port forwarding, remote debugging, and inspection with popular Java diagnostic tools.

Getting started

You can use Heroku Exec by running:

$ heroku ps:exec

If you are using Exec with a Private Spaces app, a custom buildpack will automatically be added to your app, and you’ll have to redeploy. A redeploy is NOT required for apps in the Common Runtime:

$ git commit -m "Heroku Exec" --allow-empty $ git push heroku master

After your application has deployed, you can run the command again to connect to your web dyno:

$ heroku ps:exec Establishing credentials... done Connecting to web.1 on ⬢ your-app... ~ $

By default, Heroku Exec connects to your web.1 dyno, but you can optionally specify a dyno:

$ heroku ps:exec --dyno=web.2 Establishing credentials... done Connecting to web.2 on ⬢ your-app... ~ $

If you run into problems connecting to a dyno, use the --status flag to check the status of the Exec connection:

$ heroku ps:exec --status === limitless-savannah-19617 Heroku Exec status Dyno Proxy Status Dyno Status ───── ──────────── ─────────── web.1 running up web.2 running up

Port forwarding

In addition to creating an interactive terminal session, the CLI can forward traffic on a local port to a port inside a dyno. In the following example, 9090 is both the local port and the dyno port:

$ heroku ps:forward 9090 Listening on 9090 and forwarding to web.1:9090...

Then connect your remote debugger, profiler, or even a browser to localhost:9090, and your requests will be routed through a secure socket to port 9090 in the dyno. To stop port forwarding, use CTRL+C .

SOCKS proxy

You can also use a local SOCKS proxy if you need to forward traffic on multiple ports. Start the proxy by running this command:

$ heroku ps:socks

With the proxy running, you can access any port inside the dyno. For example:

$ curl --socks5 localhost:1080 0.0.0.0:12345

To use Java debugging tools, you must first install the Heroku CLI Java plugin by running:

$ heroku plugins:install java

Then you can open a JConsole connection to a dyno by running this command locally:

$ heroku java:jconsole

The JConsole connection is routed through a secure SOCKS proxy created with SSH, which ensures that all traffic is encrypted. But JConsole will warn you that the connection is insecure because the JVM is not aware of the lower-level encryption.

Run heroku help java for a list of more Java-related commands, such as:

heroku java:visualvm

heroku java:jmap

heroku java:jstack

When Heroku Exec is enabled, the default JAVA_TOOL_OPTIONS environment variable will change to include options that enable JMX for all Java processes in your dyno. You can prevent this by running:

$ heroku config:set HEROKU_DISABLE_JMX=1

This will disable commands like heroku java:visualvm , which require JMX. But other commands such as ps:exec and java:jmap will continue to work. If you want to selectively enable JMX, you can add the $HEROKU_JMX_OPTIONS environment variable to the java command used to run your app.

Remote debugging

Many popular IDEs provide remote debugging capabilities through an SSH tunnel.

In all cases, you must first configure your application to enable remote debugging. For Node.js, you must add the --inspect=9090 to the node command that starts your app. For example, your Procfile might look like this:

web: node --inspect=9090 index.js

For Java applications, you must provide the -agentlib option to configure the Java Debug Wire Protocol (JDWP). For example:

web: java -agentlib:jdwp=transport=dt_socket,server=y,address=9090,suspend=n -jar target/myapp.jar

In both cases, the port 9090 is arbitrary.

After you change your Procfile and redeploy your app, you can start port forwarding with the Heroku Exec client:

$ heroku ps:forward 9090

Finally, connect your IDE or remote debugger to localhost:9090 .

For more information on specific vendors, please see the IDE documentation:

For most JetBrains products, including IntelliJ IDEA and WebStorm, select “Edit Configurations” and create a new “Remote” run configuration. Select port 9090 and localhost. Then start the configuration, set a break-point, and open your application.

Copying files from a dyno

To copy files from a dyno, run the following command on your local machine (not on the dyno):

$ heroku ps:copy filename

This copies the file in the dyno with the given name to a local file with the same name. You can use the -o option to specify the name of the local file. This command can only be used on formation dynos and isn’t available to one-off dynos and processes started with heroku run .

Using with Docker

If you’re packaging your app with Docker and deploying via Container Registry, using Heroku Exec is not officially supported and requires a few additional setup steps:

Ensure that your Docker image has bash , curl , openssh (version 7.6 or 7.2), and python installed. Alternatively, you can use the Heroku-16 base image.

Create a heroku-exec.sh file with the following code, and include it in the /app/.profile.d directory of your image:

[ -z "$SSH_CLIENT" ] && source <(curl --fail --retry 3 -sSL "$HEROKU_EXEC_URL")

The heroku-exec.sh file must live in /app/.profile.d , even though your WORKDIR can be different. Here’s an example of a Dockerfile command that adds the file to the correct directory:

ADD ./.profile.d /app/.profile.d

Finally, ensure the default shell is Bash by including the following line in your Dockerfile :

RUN rm /bin/sh && ln -s /bin/bash /bin/sh

If you are using Docker in a Private Space, you must add the heroku-exec.sh script to your CMD entry, as .profile.d scripts will not be run. For example:

CMD bash heroku-exec.sh && node index.js

Disabling the feature

To disable the feature, run the following command:

$ heroku features:disable runtime-heroku-exec

Then optionally remove the Heroku Exec buildpack from your app (Private Spaces only) by running:

$ heroku buildpacks:remove heroku/exec

Precompiled deployment with Private Spaces

Before you can use Heroku Exec with a Private Space and the Heroku Maven plugin, you must add the following plugin configuration in your pom.xml (note the <buildpacks> section):

<plugin> <groupId>com.heroku.sdk</groupId> <artifactId>heroku-maven-plugin</artifactId> <configuration> <buildpacks> <buildpack>https://github.com/heroku/exec-buildpack</buildpack> <buildpack>heroku/jvm</buildpack> </buildpacks> </configuration> </plugin>

Then redeploy with mvn heroku:deploy and run heroku ps:exec or other commands described in this document.

With the sbt-heroku Plugin, you must add the following configuration to your build.sbt :

herokuBuildpacks in Compile := Seq( "https://github.com/heroku/exec-buildpack", "heroku/jvm" )

Then redeploy with sbt deployHeroku and run heroku ps:exec or other commands described in this document.

With the Heroku CLI Deploy Plugin, you must add the --buildpacks heroku/exec,heroku/jvm option to any war:deploy or jar:deploy command you use.

Limitations

Connection

Each Heroku Exec connection lasts a maximum of one hour. After an hour, you might need to reconnect. Additionally, Heroku Exec is not supported in Shield Private Spaces.

Heroku Exec is not enabled for one-off dynos.

Environment variables

The SSH session created by Heroku Exec will not have the config vars set as environment variables (i.e., env in a session will not list config vars set by heroku config:set ).

Shield Private Spaces compatibility

Due to the high-compliance requirements of apps running in Shield Private Spaces, Heroku Exec is not supported.