Install
Java 21 or newer, where HttpClient can be closed. The client itself has been in the JDK since 11, and java File.java runs a single source file without a build.
java -versionRotating residential
The client keeps connections alive, and a live tunnel keeps its address, so this example builds a new client per request and closes it. Each new client opens a new tunnel through the residential gateway and prints a new address. Run it with java -Djdk.http.auth.tunneling.disabledSchemes= Rotate.java.
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class Rotate {
static final Authenticator auth = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (getRequestorType() != RequestorType.PROXY) return null;
return new PasswordAuthentication("USER", "PASS".toCharArray());
}
};
public static void main(String[] args) throws Exception {
URI proxy = URI.create("http://resi.proxymonkey.io:8000");
ProxySelector selector = ProxySelector.of(new InetSocketAddress(proxy.getHost(), proxy.getPort()));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://httpbin.org/ip"))
.timeout(Duration.ofSeconds(30))
.build();
for (int i = 0; i < 3; i++) {
try (HttpClient client = HttpClient.newBuilder()
.proxy(selector)
.authenticator(auth)
.connectTimeout(Duration.ofSeconds(10))
.build()) {
System.out.print(client.send(request, HttpResponse.BodyHandlers.ofString()).body());
}
}
}
}A static datacenter or ISP IP
On a static datacenter IP, keep one client for the whole run so connections are reused. This is the body of main, with the same imports and Authenticator as above plus java.util.List. For an ISP order, use the host and port from your dashboard.
URI proxy = URI.create("http://IP:PORT");
HttpClient client = HttpClient.newBuilder()
.proxy(ProxySelector.of(new InetSocketAddress(proxy.getHost(), proxy.getPort())))
.authenticator(auth)
.connectTimeout(Duration.ofSeconds(10))
.build();
for (String url : List.of("https://httpbin.org/ip", "https://httpbin.org/headers")) {
HttpRequest request = HttpRequest.newBuilder(URI.create(url)).timeout(Duration.ofSeconds(30)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String body = response.body();
System.out.println(response.statusCode() + " " + body.substring(0, Math.min(80, body.length())));
}Keeping one identity
One HttpClient keeps idle connections for 30 seconds by default (jdk.httpclient.keepalive.timeout), and requests to the same host in that window reuse a tunnel and its exit address. That is fine for a short flow and not a guarantee. For a residential IP that has to hold across a login, use a sticky session; the session setting for your account is in the dashboard. Cookies are off unless you add .cookieHandler(new CookieManager()) to the builder.