<!--
  canonical-url: https://www.avonture.be/blog/docker-networking-troubleshooting
  published:     2025-12-22
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Troubleshooting for Docker containers - Accessing the other one

> Troubleshoot Docker container networking - test ports, DNS, and fix proxy issues so one container can reliably call another API on the same network.

---
![Troubleshooting for Docker containers - Accessing the other one](/img/v2/autopsy_binary_crime.webp)

**TL;DR**

This article details troubleshooting steps for Docker containers unable to communicate, specifically when one container needs to access another's API on the same network. It systematically checks network configuration, port accessibility, and DNS resolution between containers. The ultimate solution involved configuring `no_proxy` environment variables within the consumer container to bypass an interfering proxy for internal Docker network addresses.

The situation: I have two containers; one called `provider` and the other one called `consumer`. The `consumer` should be able to run an API on the `provider`.

And ... it didn't work: something in my configuration is not correct because I get connection errors when trying to call the `provider`, let's start the investigation and understand the solution.

In the rest of this article, let's call them like that: `provider` for the first container and `consumer` for the second one.

## First, they should be on the same network

First, they should be on the same Docker network; otherwise, there's no chance of making it work. *If you need the opposite — reaching a service running on your host from inside a container — read [Using Docker network and the extra\_hosts property](/blog/docker-network-and-extra-hosts).*

By running `docker ps` you'll get the `container_id` and the `name` of your two containers.

The command to retrieve the name of the Docker network is `docker inspect --format '{{json .NetworkSettings.Networks}}' CONTAINER_NAME | jq` ([`jq`](/blog/linux-jq) is the Swiss-army knife for JSON on the command line) so, for the first container, please run `docker inspect --format '{{json .NetworkSettings.Networks}}' provider | jq` and `docker inspect --format '{{json .NetworkSettings.Networks}}' consumer | jq` for the second.

You'll get something like that:

```json
{
  "your_network": {
    "IPAMConfig": null,
    "Links": [
    ],
    "Aliases": [
      "facade",
      "facade"
    ],
    "DriverOpts": null,
    "GwPriority": 0,
    "NetworkID": "528b60827ec7469dfb2c604c3443ac716f8fa1f3d1934089f49e53f6e65500ca",
    "EndpointID": "be75366d271b090f3d47f236ddff0236993af02a73c5d501f44fbef8f351be5e",
    "Gateway": "192.168.0.1",
    "IPAddress": "192.168.0.4",
    "MacAddress": "62:5b:7b:9e:12:fe",
    "IPPrefixLen": 24,
    "IPv6Gateway": "",
    "GlobalIPv6Address": "",
    "GlobalIPv6PrefixLen": 0,
    "DNSNames": [
      "facade",
      "5abd45eecfa3"
    ]
  }
}
```

In this example, the network is called `your_network`. Just make sure you have the same for both containers. Also, make sure you have the same `Gateway` too (`192.168.0.1` in this example).

> **Ok, they're running on the same network.:**

## Then, testing the internal port for both containers

Please run `docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"` to get the list of running containers and their ports (extern/intern).

You'll get something like this:

```bash
CONTAINER ID   NAMES    PORTS
5abd45eecfa3   consumer   0.0.0.0:8001->8000/tcp, [::]:8001->8000/tcp
a95b6174beb9   provider     0.0.0.0:8888->8000/tcp, [::]:8888->8000/tcp
```

So they both are running port `8000` internally but the `consumer` is exposed on the host using port `8001` and `provider` on port `8888`.

In the previous chapter, we just saw that the network is called `your_network`.

We can ensure the process running on port `8000` in both containers is running by executing `docker inspect -f '{{.NetworkSettings.Networks.your_network.IPAddress}}' consumer` in the console to get the IP of that container. In my case, I get `192.168.0.4` as response.

Now that we've it, we can test the internal port:

```bash
$ telnet 192.168.0.4 8000

Trying 192.168.0.4...
Connected to 192.168.0.4.
Escape character is '^]'.
```

Press `CTRL`+`C` to quit.

> **Ok, both containers have a service running on their internal port.:**

## Third, testing the external port for both containers

We've seen containers are running on port `8000` internally but one is mapping the port `8001` on the host and `8888` for the second one.

We can run `telnet 127.0.0.1 8001` and `telnet 127.0.0.1 8888` to test that port. **See, here, since we're accessing exposed ports, we're using our local host IP address.**

If you know that the service is a web service, you can run `curl -vvv 127.0.0.1:8001` to make sure the service is working fine and the delivered answer meets your expectations:

```txt
*   Trying 127.0.0.1:8001...
* Connected to 127.0.0.1 (127.0.0.1) port 8001 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:8001
> User-Agent: curl/7.76.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Sun, 14 Dec 2025 08:17:16 GMT
< server: uvicorn
< content-length: 106
< content-type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
```

> **Ok, both containers are correctly exposed on their external port.:**

## Fourthly, testing connectivity between the two containers

Run `docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"` again to get the container name and its associated container ID back.

In our preamble, we've said: the `consumer` should be able to run an API from the `provider` so let's jump in the `consumer` by creating a console. We'll use the CONTAINER\_ID of the consumer and we'll connect as `root`:

```bash
$ docker exec --user root -it 5abd45eecfa3 sh
```

We'll first try `ping` to see if we can connect to the `provider` container:

```bash
$ apt-get update
$ apt-get install -y iputils-ping
```

Once done, try `ping` followed by the container name (we've already identified `provider` and `consumer` as our container names thanks to our `docker ps` command).

```bash
$ ping provider

PING provider (192.168.0.3) 56(84) bytes of data.
64 bytes from provider (192.168.0.3): icmp_seq=1 ttl=64 time=0.176 ms
64 bytes from provider (192.168.0.3): icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from provider (192.168.0.3): icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from provider (192.168.0.3): icmp_seq=4 ttl=64 time=0.068 ms
```

Press `CTRL`+`C` to stop.

> **Ok, our consumer can reach the provider by name (ping works).:**
>
> This means that the DNS resolution is working fine.

### Testing the port

Still in the `consumer` container, install `telnet` if needed

```bash
$ apt-get update
$ apt-get install -y telnet
```

Then run `telnet provider 8000` i.e. the name of the container and its internal port (not the exposed one)

```bash
$ telnet provider 8000

Trying 192.168.0.3...
Connected to bim_provider_api.
Escape character is '^]'.
```

> **Trying the exposed port:**
>
> Just rerun the last `telnet` command but using port `8888` this time: it'll not work.
>
> By using the container name with telnet, we should use the internal port; not the exposed one.

> **Ok, the transport layer (telnet) is working too.:**
>
> `telnet` is used to test the **transport layer** (layer #4 in the [OSI model](https://en.wikipedia.org/wiki/OSI_model)) and our test here is showing it's working.

### Testing the application

Now that we know containers can communicate, let's try the **application layer** (layer #7 in the [OSI model](https://en.wikipedia.org/wiki/OSI_model)).

In my use case, the `provider` container is offering an API so I should be able to reach it using `curl`.

```bash
$ curl -v http://provider:8000
```

In my situation, this is where I got an error and the dump is showing something like this:

```text
<body><div class="message-container">
<div class="logo"></div>
<h1>504 DNS look up failed</h1>
<p>The webserver reported that an error occurred while trying to access the website. Please return to the previous page.</p>
<table><tbody>
<tr>
<td>URL</td>
<td>http://provider:8000/</td>
</tr>
</tbody></table>
</div></body>
```

**Bingo! The problem is ... a proxy.**

The request was intercepted by a proxy and that one is denying the request.

We should tell it to ignore requests made to our container.

```bash
export no_proxy="provider,192.168.0.0/24,127.0.0.1,localhost"
export NO_PROXY="provider,192.168.0.0/24,127.0.0.1,localhost"
```

* `provider` is the name of our container,
* `192.168.0.0/24` is the IP range for the Docker subnet (you can retrieve it by running `docker network inspect your_network | jq -r '.[].IPAM.Config[0].Subnet'`)
* the well-known `127.0.0.1,localhost` is our localhost

> **The no\_proxy variable:**
>
> To make sure all tools (`curl`, `wget`, `apt-get`, ...) are well using the `no_proxy` variable, it's recommended to use both notation: lower and upper case.

Now, finally, the command I use to consume my API looks like `curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' http://provider:8000/api/v1/fetch`.

## Fifthly, finding the solution

If you came across this article because you had the same problem as me, the solution is now simple: make sure your Docker image is configured to have a `no_proxy` variable with the correct values.

This can be done using a `no_proxy` variable in your `compose.yaml` file, here, just for the illustration, a sample way to do this:

```yaml
services:
  consumer:
    image: your_image
    build:
      context: .
      dockerfile: Dockerfile
      args:
        - HTTP_NO_PROXY=${HTTP_NO_PROXY:-provider,localhost,.local,127.0.0.1,192.168.0.0/24}
```

Now, in your `Dockerfile` just do something like:

```Dockerfile
# syntax=docker/dockerfile:1
ARG HTTP_NO_PROXY="localhost,.local,127.0.0.1,192.168.0.0/24"

FROM python:3.14-slim AS production

ARG HTTP_NO_PROXY

ENV no_proxy="${HTTP_NO_PROXY}" \
    NO_PROXY="${HTTP_NO_PROXY}"
```

Create your containers again and tadaaaa! it'll work.

In our example here, we finally determined that it was not the network layer that was at fault, but rather the layer where the proxy took control: the application layer.
