Back to Blog

Configuring Proxies in Java Applications: Spring Boot, OkHttp, and RestTemplate - Complete Guide with Code

A complete guide to configuring proxies in corporate Java applications: Spring Boot, OkHttp, RestTemplate, WebClient — with code examples and proxy selection recommendations.

📅August 12, 2026
```html

Enterprise Java applications regularly interact with external APIs, parse data, or operate in isolated corporate networks — and in each of these cases, sooner or later, the question of routing traffic through a proxy server arises. Configuring a proxy in Java seems like a simple task until you encounter the fact that RestTemplate, OkHttp, and WebClient behave differently, and JVM system properties do not work everywhere. This guide provides specific code examples, explanations of pitfalls, and recommendations for selecting the type of proxy for different tasks.

Why Java Applications Need Proxies

Java remains one of the main languages for enterprise development. Spring Boot services, microservice architectures, batch tasks, ETL pipelines — all of these regularly make HTTP requests to the outside world. And in each of these scenarios, proxies solve specific tasks:

  • Corporate networks with mandatory proxy gateways. In many companies, all outgoing traffic goes through a corporate proxy (Squid, Zscaler, BlueCoat). Without its configuration, the application simply cannot access the internet.
  • Parsing and data collection. Services that collect data from external sites (prices, quotes, news) use proxies to bypass rate limits and IP blocks.
  • Geo-testing. QA teams check how an API or website behaves from different regions — proxies allow emulating requests from the desired country.
  • Bypassing restrictions on the target API side. Some external APIs have limits on the number of requests from a single IP. Proxy rotation allows distributing the load.
  • Security and anonymization. Hiding the real IP of the application when accessing external services is standard practice for sensitive integrations.

Depending on the task, approaches to configuring proxies in Java can vary significantly. Global JVM system properties are the simplest option, but they do not work with some HTTP clients. OkHttp and WebClient require explicit configuration. Let's break down each case in order.

Global Configuration via JVM System Properties

The quickest way to route all HTTP traffic of a Java application through a proxy is to use JVM system properties. This works for the standard HttpURLConnection and many libraries that use it under the hood.

You can set the proxy in several ways:

1. Via JVM arguments at startup:

java -Dhttp.proxyHost=proxy.example.com \
     -Dhttp.proxyPort=8080 \
     -Dhttps.proxyHost=proxy.example.com \
     -Dhttps.proxyPort=8080 \
     -Dhttp.nonProxyHosts="localhost|127.0.0.1|*.internal.corp" \
     -jar myapp.jar

2. Via application code (e.g., in the main method or in @PostConstruct):

System.setProperty("http.proxyHost", "proxy.example.com");
System.setProperty("http.proxyPort", "8080");
System.setProperty("https.proxyHost", "proxy.example.com");
System.setProperty("https.proxyPort", "8080");
// Exceptions — hosts that should not go through the proxy
System.setProperty("http.nonProxyHosts", "localhost|127.0.0.1|*.internal.corp");

3. Via the application.properties file in Spring Boot (subsequently applied via @PostConstruct):

# application.properties
proxy.host=proxy.example.com
proxy.port=8080
proxy.username=user
proxy.password=secret

⚠️ Important to Know

JVM system properties only work for HttpURLConnection. OkHttp, Apache HttpClient, and Reactor Netty (WebClient) ignore these properties — they require explicit configuration as described below.

If the proxy requires authentication, use Authenticator:

Authenticator.setDefault(new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if (getRequestorType() == RequestorType.PROXY) {
            return new PasswordAuthentication("username", "password".toCharArray());
        }
        return null;
    }
});

Proxies in Spring Boot: RestTemplate and Apache HttpClient

RestTemplate is the standard synchronous HTTP client in Spring. By default, it uses SimpleClientHttpRequestFactory, which relies on HttpURLConnection and reads JVM system properties. However, for more flexible configuration (timeouts, connection pool, authenticated proxies), it is recommended to use Apache HttpClient as the backend.

Maven Dependency:

<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

Configuring RestTemplate with Proxy via Apache HttpClient 5:

@Configuration
public class RestTemplateConfig {

    @Value("${proxy.host}")
    private String proxyHost;

    @Value("${proxy.port}")
    private int proxyPort;

    @Value("${proxy.username:}")
    private String proxyUsername;

    @Value("${proxy.password:}")
    private String proxyPassword;

    @Bean
    public RestTemplate restTemplate() {
        HttpHost proxy = new HttpHost("http", proxyHost, proxyPort);

        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        if (!proxyUsername.isEmpty()) {
            credentialsProvider.setCredentials(
                new AuthScope(proxyHost, proxyPort),
                new UsernamePasswordCredentials(proxyUsername, proxyPassword.toCharArray())
            );
        }

        CloseableHttpClient httpClient = HttpClients.custom()
            .setProxy(proxy)
            .setDefaultCredentialsProvider(credentialsProvider)
            .build();

        HttpComponentsClientHttpRequestFactory factory =
            new HttpComponentsClientHttpRequestFactory(httpClient);
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(10000);

        return new RestTemplate(factory);
    }
}

This configuration allows you to move proxy parameters to application.properties or environment variables, which is critical for prod/staging/dev environments with different proxies.

If you need some requests to go through the proxy while others go directly, create two separate RestTemplate beans with different names and use @Qualifier for injecting the required one.

Proxies in Spring WebClient (Reactive Stack)

WebClient is a reactive HTTP client in Spring built on Reactor Netty. It does not read JVM system properties for proxies — configuration is done through ProxyProvider when creating the client.

Dependency (included in spring-boot-starter-webflux):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Configuring WebClient with HTTP Proxy:

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient() {
        HttpClient httpClient = HttpClient.create()
            .proxy(proxy -> proxy
                .type(ProxyProvider.Proxy.HTTP)
                .host("proxy.example.com")
                .port(8080)
                .username("user")
                .password(user -> "password")
            );

        ClientHttpConnector connector =
            new ReactorClientHttpConnector(httpClient);

        return WebClient.builder()
            .clientConnector(connector)
            .build();
    }
}

For SOCKS5 Proxy in WebClient:

HttpClient httpClient = HttpClient.create()
    .proxy(proxy -> proxy
        .type(ProxyProvider.Proxy.SOCKS5)
        .host("socks5.proxy.example.com")
        .port(1080)
        .username("user")
        .password(user -> "password")
    );

💡 Configuration Tip

In reactive applications, it is often necessary to create multiple instances of WebClient with different proxies for different external services. Use WebClient.Builder as a prototype bean and override settings via .mutate().

Configuring Proxies in OkHttp

OkHttp is a popular HTTP library used by many Java and Android applications, as well as some Spring integrations (e.g., Feign with OkHttp backend). It has its own proxy configuration mechanism and also does not read JVM system properties.

Basic Configuration of HTTP/HTTPS Proxy in OkHttp:

import okhttp3.*;
import java.net.InetSocketAddress;
import java.net.Proxy;

// Create a proxy
Proxy proxy = new Proxy(
    Proxy.Type.HTTP,
    new InetSocketAddress("proxy.example.com", 8080)
);

// Proxy authentication
Authenticator proxyAuthenticator = (route, response) -> {
    String credential = Credentials.basic("username", "password");
    return response.request().newBuilder()
        .header("Proxy-Authorization", credential)
        .build();
};

// Build the client
OkHttpClient client = new OkHttpClient.Builder()
    .proxy(proxy)
    .proxyAuthenticator(proxyAuthenticator)
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build();

// Example request
Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .build();

try (Response response = client.newCall(request).execute()) {
    System.out.println(response.body().string());
}

Integrating OkHttp with Spring Boot via Bean:

@Configuration
@ConditionalOnProperty(name = "proxy.enabled", havingValue = "true")
public class OkHttpConfig {

    @Value("${proxy.host}")
    private String proxyHost;

    @Value("${proxy.port}")
    private int proxyPort;

    @Bean
    public OkHttpClient okHttpClient() {
        Proxy proxy = new Proxy(
            Proxy.Type.HTTP,
            new InetSocketAddress(proxyHost, proxyPort)
        );

        return new OkHttpClient.Builder()
            .proxy(proxy)
            .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES))
            .build();
    }
}

Note the @ConditionalOnProperty — this allows enabling the proxy only in the necessary environments through configuration without changing the code.

If you are using OkHttp together with residential proxies for data parsing, it is important to configure the connection pool correctly. Residential proxies often have higher latency compared to datacenter proxies, so increase the timeouts and reduce the pool size to avoid exhausting available connections.

SOCKS5 Proxies in Java: Features and Examples

SOCKS5 is a lower-level protocol compared to HTTP proxies. It operates at the transport layer and supports any protocols (HTTP, HTTPS, FTP, etc.), as well as DNS resolution on the proxy side. For Java applications, SOCKS5 is especially useful when you need to proxy not only HTTP but also other TCP connections.

SOCKS5 via JVM System Properties:

System.setProperty("socksProxyHost", "socks5.proxy.example.com");
System.setProperty("socksProxyPort", "1080");
System.setProperty("java.net.socks.username", "user");
System.setProperty("java.net.socks.password", "password");

SOCKS5 in OkHttp (via java.net.Proxy):

Proxy socks5Proxy = new Proxy(
    Proxy.Type.SOCKS,
    new InetSocketAddress("socks5.proxy.example.com", 1080)
);

OkHttpClient client = new OkHttpClient.Builder()
    .proxy(socks5Proxy)
    .build();

Important Feature of SOCKS5 and DNS: By default, Java resolves DNS locally and passes the IP address through the proxy. This can expose the real DNS request. To ensure DNS resolution also goes through the proxy, use the following approach with OkHttp:

// Custom DNS that forces resolution through SOCKS5
OkHttpClient client = new OkHttpClient.Builder()
    .proxy(socks5Proxy)
    .dns(hostname -> {
        // Return the unresolved host — OkHttp will pass it to the proxy
        return Collections.singletonList(InetAddress.getByName(hostname));
    })
    .build();

When to Choose SOCKS5 vs HTTP Proxies

Criterion HTTP Proxy SOCKS5 Proxy
Protocols HTTP/HTTPS Any TCP/UDP
DNS through Proxy Depends on implementation Supported
Compatibility with Java Native Native (java.net.Proxy.Type.SOCKS)
Usage Corporate gateways, web scraping Anonymization, non-standard protocols

Proxy Rotation in Java Applications

If an application makes a large number of requests to a single resource, using a single proxy IP will quickly lead to blocking. Proxy rotation — switching between different IP addresses — solves this problem. In Java, this can be implemented in several ways.

Option 1: Rotation via Rotating Proxy Endpoint

The simplest approach is to use a proxy provider with a single endpoint that automatically changes the IP with each request or at a specified interval. You specify one host and port, and the rotation occurs on the provider's side. No code for rotation needs to be written.

Option 2: Rotation on the Application Side via Proxy List

@Component
public class ProxyRotator {

    private final List<ProxyConfig> proxies;
    private final AtomicInteger counter = new AtomicInteger(0);

    public ProxyRotator(@Value("${proxy.list}") List<String> proxyList) {
        this.proxies = proxyList.stream()
            .map(this::parseProxy)
            .collect(Collectors.toList());
    }

    public OkHttpClient getClientWithNextProxy() {
        int index = counter.getAndIncrement() % proxies.size();
        ProxyConfig config = proxies.get(index);

        Proxy proxy = new Proxy(
            Proxy.Type.HTTP,
            new InetSocketAddress(config.getHost(), config.getPort())
        );

        return new OkHttpClient.Builder()
            .proxy(proxy)
            .build();
    }

    private ProxyConfig parseProxy(String proxyStr) {
        // Parse the string in the format "host:port" or "user:pass@host:port"
        String[] parts = proxyStr.split(":");
        return new ProxyConfig(parts[0], Integer.parseInt(parts[1]));
    }
}

Option 3: Rotation via ProxySelector

Java provides a built-in mechanism ProxySelector, which allows dynamically selecting proxies based on the destination URL. This works with HttpURLConnection and Apache HttpClient:

ProxySelector.setDefault(new ProxySelector() {
    private final List<Proxy> proxyPool = Arrays.asList(
        new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy1.example.com", 8080)),
        new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy2.example.com", 8080)),
        new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
    );
    private final AtomicInteger idx = new AtomicInteger(0);

    @Override
    public List<Proxy> select(URI uri) {
        // Logic for selection by domain can be added
        int i = idx.getAndIncrement() % proxyPool.size();
        return Collections.singletonList(proxyPool.get(i));
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        // Logic for handling unavailable proxy
        log.warn("Proxy failed: {}", sa);
    }
});

Which Proxy Type to Choose for Java Tasks

The choice of proxy type depends on the specific task. For enterprise Java applications, three main types are usually considered:

Proxy Type Speed Anonymity Best for
Datacenter Proxies High Medium Scraping open data, API testing, high load
Residential Proxies Medium High Scraping secure sites, geo-testing, bypassing blocks
Mobile Proxies Medium Maximum Integrations with mobile APIs, services with strict anti-fraud protection

Practical Recommendations for Types of Tasks:

  • Corporate Gateway (Squid, Zscaler): The type of proxy is determined by the IT department. Use HTTP proxies with authentication through Apache HttpClient or JVM system properties.
  • Scraping Public Data (news, quotes, open APIs): Datacenter proxies are the optimal choice for speed and cost.
  • Scraping e-commerce (Wildberries, Ozon, Amazon): Residential proxies with rotation. These platforms actively block datacenter IPs.
  • Geo-testing (checking localization, prices by region): Residential proxies with country/city selection.
  • Integration with Mobile Services and Applications: Mobile proxies — IPs from real mobile networks best imitate real users.

Common Mistakes When Configuring Proxies in Java and How to Fix Them

Even experienced developers encounter the same issues when configuring proxies in Java. Let's discuss the most common ones.

1. Proxy is configured, but traffic still goes directly

Reason: You set JVM system properties, but you are using OkHttp or Reactor Netty (WebClient), which ignore them.
Solution: Configure the proxy explicitly in the configuration of the specific HTTP client, as shown in the sections above.

2. javax.net.ssl.SSLHandshakeException when HTTPS through proxy

Reason: The corporate proxy performs SSL inspection (MITM), replacing the certificate. Java does not trust the corporate CA.
Solution: Import the corporate certificate into the Java truststore:

keytool -import -trustcacerts \
  -alias corporate-ca \
  -file corporate-ca.crt \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -storepass changeit

3. java.net.ConnectException: Connection refused

Reasons: Incorrect host or port of the proxy; the proxy server is unavailable; firewall blocks the connection.
Diagnosis:

# Check proxy availability
curl -x http://proxy.example.com:8080 https://httpbin.org/ip

# Or via telnet
telnet proxy.example.com 8080

4. Proxy works for HTTP but not for HTTPS

Reason: Only http.proxyHost/Port properties are set, but not https.proxyHost/Port.
Solution: Set both sets of properties. For HTTPS through HTTP proxy, the CONNECT tunneling method is used — ensure that the proxy supports it.

5. 407 Proxy Authentication Required

Reason: The proxy requires authentication, but it is not configured.
Solution: Add Authenticator for JVM system properties or configure CredentialsProvider for Apache HttpClient / proxyAuthenticator for OkHttp (examples above).

6. Memory leak when rotating proxies

Reason: A new instance of OkHttpClient is created for each request. Each client maintains its own pool of threads and connections.
Solution: Reuse clients. Create a pool of several clients (one for each proxy) and rotate them instead of creating new ones.

7. Enabling debug logging for diagnosis

# application.properties — enable logs for proxy diagnosis
logging.level.org.apache.http=DEBUG
logging.level.org.apache.http.wire=DEBUG
logging.level.reactor.netty.http.client=DEBUG

# For JVM — system property
-Djava.net.debug=all

Conclusion

Configuring proxies in Java applications requires an understanding of which HTTP client is used under the hood. JVM system properties provide a quick start for HttpURLConnection, but OkHttp, WebClient, and Apache HttpClient require explicit configuration. For enterprise applications, it is recommended to externalize proxy parameters into application.properties and use Spring profiles for different environments. It is better to delegate proxy rotation to a provider with a rotating endpoint — this is easier and more reliable than implementing it yourself.

If your Java application is scraping data from secure platforms or requires high anonymity for external requests, we recommend considering residential proxies — they have real IPs of home users, significantly reducing the likelihood of blocks from anti-fraud systems. For high-load scraping of open data, datacenter proxies are optimal — they provide maximum speed at a lower cost of traffic.

```