Skip to content

Home

java-ngrok - a Java wrapper for ngrok

Version Java Versions Coverage Build Code Quality Docs GitHub License

java-ngrok is a Java wrapper for ngrok that manages its own binary, making ngrok available via a convenient Java API.

ngrok is a reverse proxy that opens secure tunnels from public URLs to localhost. It's perfect for rapid development (test webhooks, demo local websites, enable SSH access), establishing ingress to external networks and devices, building production APIs (traffic policies, OAuth, load balancing), and more. And it's made even more powerful with native Java integration through the java-ngrok client.

Installation

java-ngrok is available on Maven Central.

If you want ngrok to be available from the command line, pyngrok can be installed using pip to manage that for you.

Open a Tunnel

To open a tunnel, use the NgrokClient's connect() method, which returns a Tunnel, and this returned object has a reference to the public URL generated by ngrok, which can be retrieved with getPublicUrl().

final NgrokClient ngrokClient = new NgrokClient.Builder().build();

// Open a HTTP tunnel on the default port 80
// <Tunnel: "https://<public_sub>.ngrok.io" -> "http://localhost:80">
final Tunnel httpTunnel = ngrokClient.connect();

// Open a SSH tunnel
// <Tunnel: "tcp://0.tcp.ngrok.io:12345" -> "localhost:22">
final CreateTunnel sshCreateTunnel = new CreateTunnel.Builder()
        .withProto(Proto.TCP)
        .withAddr(22)
        .build();
final Tunnel sshTunnel = ngrokClient.connect(sshCreateTunnel);

// Open a named tunnel from the config file
final CreateTunnel createNamedTunnel = new CreateTunnel.Builder()
        .withName("my-config-file-tunnel")
        .build();
final Tunnel namedTunnel = ngrokClient.connect(createNamedTunnel);

// Open an Internal Endpoint that's load balanced
// <Tunnel: "https://some-endpoint.internal" -> "http://localhost:9000">
final CreateTunnel createInternalEndpoint = new CreateTunnel.Builder()
        .withAddr("9000")
        .withDomain("some-endpoint.internal")
        .withPoolingEnabled(true)
        .build();
final Tunnel internalEndpoint = ngrokClient.connect(createInternalEndpoint);

The connect() method can also take a CreateTunnel (which can be built through its Builder) that allows you to pass additional properties that are supported by ngrok (or withName() to use a tunnel defined in ngrok's config file), as documented here.

Note: ngrok v2's default behavior for http when no additional properties are set is to open two tunnels, one http and one https. java-ngroks connect method will return a reference to the http tunnel in this case. If only a single tunnel is needed, use withBindTls(true) and a reference to the https tunnel will be returned.

Get Active Tunnels

It can be useful to ask the ngrok client what tunnels are currently open. This can be accomplished with the getTunnels() method, which returns a list of Tunnel objects.

// [<Tunnel: "https://<public_sub>.ngrok.io" -> "http://localhost:80">]
final List<Tunnel> tunnels = ngrokClient.getTunnels();

Close a Tunnel

All open tunnels will automatically be closed when the Java process terminates, but we can also close them manually with disconnect(String).

// The Tunnel returned from methods like connect(), getTunnels(), etc. contains the public URL
ngrokClient.disconnect(publicUrl);

Expose Other Services

Using ngrok you can expose any number of non-HTTP services, for instances databases, game servers, etc. This can be accomplished by using java-ngrok to open a TCP tunnel to the desired service.

// Open a tunnel to MySQL with a Reserved TCP Address
// <NgrokTunnel: "tcp://1.tcp.ngrok.io:12345" -> "localhost:3306">
final CreateTunnel mysqlCreateTunnel = new CreateTunnel.Builder()
        .withProto(Proto.TCP)
        .withAddr(3306)
        .withRemoteAddr("1.tcp.ngrok.io:12345")
        .build();
final Tunnel mysqlTunnel = ngrokClient.connect(mysqlCreateTunnel);

You can also serve up local directories via ngrok's built-in fileserver.

// Open a tunnel to a local file server
// <NgrokTunnel: "https://<public_sub>.ngrok.io" -> "file:///">
final CreateTunnel fileserverCreateTunnel = new CreateTunnel.Builder()
        .withAddr("file:///")
        .build();
final Tunnel fileserverTunnel = ngrokClient.connect(fileserverCreateTunnel);

Tunnel Configuration

It is possible to configure the tunnel when it is created, for instance adding authentication, a subdomain, or other additional tunnel configurations that are supported by ngrok. This is accomplished by using CreateTunnel.Builder to set what properties will be used when the tunnel is created. Here is an example that opens a tunnel with subdomain foo, requires basic authentication for requests, and defines a circuit breaker.

final CreateTunnel createTunnel = new CreateTunnel.Builder()
        .withSubdomain("foo")
        .withAuth("username:password")
        .withCircuitBreaker(50)
        .build();

final Tunnel tunnel = ngrokClient.connect(createTunnel);

If you already have a tunnel defined in ngrok's config file, you can start it by its name.

final CreateTunnel createTunnel = new CreateTunnel.Builder()
        .withName("my-config-file-tunnel")
        .build();

final Tunnel tunnel = ngrokClient.connect(createTunnel);

ngrok's API

The api() method allows you to use the local ngrok agent to make requests against the ngrok API, if you have set an API key. For example, here's how you would reserve a ngrok domain, then create a Cloud Endpoint with an associated traffic policy:

final String domain = "some-domain.ngrok.dev";
final ApiResponse domainResponse = ngrokClient.api(
        List.of("reserved-domains", "create",
                "--domain", domain));
final ApiResponse endpointResponse = ngrokClient.api(
        List.of("endpoints", "create",
                "--bindings", "public",
                "--url", String.format("https://%s", domain),
                "--traffic-policy-file", "policy.yml"));

Event Logs

When ngrok emits logs, java-ngrok can surface them to a callback function. To register this callback, use JavaNgrokConfig.Builder.withLogEventCallback(Function<NgrokLog, Void>), as show here:

final Function<NgrokLog, Void> logEventCallback = ngrokLog -> {
    System.out.println(ngrokLog.getLine());
    return null;
};

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withLogEventCallback(logEventCallback)
        .build();

final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

If these events aren't necessary for your use case, some resources can be freed up by turning them off. JavaNgrokConfig.Builder.withoutMonitoring() will disable logging, or you can call NgrokProcess.ProcessMonitor.stop() to stop monitoring on a running process.

Configuration

JavaNgrokConfig

java-ngroks interactions with the ngrok binary can be configured using JavaNgrokConfig, which can then be passed to NgrokClient.

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withRegion(Region.AU)
        .withMaxLogs(10);

final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

Note: If ngrok is not already installed at JavaNgrokConfig.getNgrokPath, it will be installed the first time most methods in NgrokClient are called.

If you need to customize the installation of ngrok, perhaps specifying a timeout, proxy, use a custom mirror for the download, etc., you can do so by leveraging the NgrokInstaller.

Setting the authtoken or api_key

Running ngrok with an auth token and API key enables access to more features available on your account (for instance, multiple concurrent tunnels, custom domains, use of Internal Endpoints, etc). You can obtain your auth token and generate API keys from the ngrok dashboard, then install it to ngrok’s config file.

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withAuthToken("<NGROK_AUTHTOKEN>")
        .withApiKey("<NGROK_API_KEY>")
        .build();

final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

You could instead define NGROK_AUTHTOKEN or NGROK_API_KEY as environment variables, if you don’t want to define them in code.

Config File

By default, ngrok will look for its config file in the default location. You can override this behavior with JavaNgrokConfig.Builder.withConfigPath(Path).

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withConfigPath(Path.of("opt", "ngrok", "config.yml"))
        .build();

 final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

Binary Path

The java-ngrok package manages its own ngrok binary. You can use your ngrok binary if you want by setting it with JavaNgrokConfig.Builder.withNgrokPath(Path) and passing that config to NgrokClient.

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withNgrokPath(Path.of("usr", "local", "bin", "ngrok"))
        .build();

final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

ngrok Version Compatibility

java-ngrok is compatible with ngrok v2 and v3, but by default it will install v3. To install v2 instead, set the version with JavaNgrokConfig.Builder.withNgrokVersion(NgrokVersion) and CreateTunnel.Builder.withNgrokVersion(NgrokVersion).

final JavaNgrokConfig javaNgrokConfig = new JavaNgrokConfig.Builder()
        .withNgrokVersion(NgrokVersion.V2)
        .build();

final NgrokClient ngrokClient = new NgrokClient.Builder()
        .withJavaNgrokConfig(javaNgrokConfig)
        .build();

// Open a V2 tunnel
// <Tunnel: "http://<public_sub>.ngrok.io" -> "http://localhost:80">
final CreateTunnel v2Tunnel = new CreateTunnel.Builder()
        .withNgrokVersion(NgrokVersion.V2)
        .build();
final Tunnel sshTunnel = ngrokClient.connect(v2Tunnel);

Command Line Usage

Assuming you have also installed pyngrok, all features of ngrok are available on the command line.

ngrok http 80

For details on how to fully leverage ngrok from the command line, see ngrok's official documentation.

Java 8

Version Java Versions Coverage Build Docs GitHub License

A Java 8-compatible build was previously maintained in the 1.4.x branch. While it is no longer supported, it is available through the java8-ngrok artifact instead on Maven Central.

For more details on what differs in the java8-ngrok dependency, see the "Java 8" section of the docs.