Introduction

When a Java application running on the host tries to connect to a service running inside a Docker container, connection refused errors occur if the container port is not properly mapped or if the Java code uses the wrong hostname. Docker's networking model isolates container services from the host by default.

This issue commonly affects developers running databases, message queues, or APIs in Docker while the Java application runs locally.

Symptoms

  • Java application throws "java.net.ConnectException: Connection refused" when connecting to localhost
  • Same service is accessible via docker exec from inside another container
  • Error occurs only when the Java app runs on the host, not when it runs in a container

Common Causes

  • Container port not published with -p flag (not mapped to host)
  • Java code connects to localhost but the service listens on a container-internal port
  • Docker network isolation prevents host-to-container communication on custom networks

Step-by-Step Fix

  1. 1.Verify the container port is published: Map the container port to the host.
  2. 2.```bash
  3. 3.# Check if the port is published:
  4. 4.docker ps
  5. 5.# Look for PORTS column: 0.0.0.0:5432->5432/tcp

# If not published, recreate with -p: docker run -d -p 5432:5432 --name postgres postgres:15

# Verify connectivity from host: telnet localhost 5432 # or nc -zv localhost 5432 ```

  1. 1.Use the correct hostname for Java HttpClient: Connect to the published port on localhost.
  2. 2.```java
  3. 3.import java.net.URI;
  4. 4.import java.net.http.HttpClient;
  5. 5.import java.net.http.HttpRequest;
  6. 6.import java.net.http.HttpResponse;

// When service runs in Docker with -p 8080:8080 HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/api/data")) .GET() .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); ```

  1. 1.Handle connection failures gracefully: Add retries and proper error handling.
  2. 2.```java
  3. 3.public String fetchWithRetry(String url, int maxRetries) throws Exception {
  4. 4.HttpClient client = HttpClient.newBuilder()
  5. 5..connectTimeout(Duration.ofSeconds(5))
  6. 6..build();

for (int attempt = 1; attempt <= maxRetries; attempt++) { try { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .timeout(Duration.ofSeconds(10)) .GET() .build();

return client.send(request, HttpResponse.BodyHandlers.ofString()).body(); } catch (HttpConnectTimeoutException | ConnectException e) { if (attempt == maxRetries) throw e; Thread.sleep(1000L * attempt); } } throw new RuntimeException("Should not reach here"); } ```

Prevention

  • Use docker-compose to manage multi-container applications with consistent networking
  • Use Testcontainers for integration tests instead of manually managed containers
  • Implement health checks that verify connectivity before starting the application
  • Document required Docker port mappings in the project README