Post

Why 'localhost' Fails in Docker: Exploring Bridge Networks and Solutions

Introduction

In this post, we will discuss an issue related to connecting an application container and a PostgreSQL container via TypeORM using docker-compose. Specifically, the connection fails when the host is set to localhost.

This is a common issue for Docker users, so let’s dive into it.

Let’s begin.


Issue Description

As mentioned in the introduction, we attempted to run an application container and a PostgreSQL container using docker-compose. However, the error shown in the image below occurred:

5-1

Why does this happen?

The issue arises because localhost refers to the internal IP (127.0.0.1) of the container itself. This means that instead of pointing to the PostgreSQL container, it refers to the internal network of the application container.

In short, PostgreSQL is not within the network space of the application container, causing the connection to fail.

Solution

The database host is managed through the .env file. As shown below, we can use either 172.17.0.1 or host.docker.internal as the DB_HOST.

5-2


Why do 172.17.0.1 and host.docker.internal work?

To understand this, consider the following flow of a network request sent by a Docker container:

container(eth0) => veth => docker0(bridge) => Host Network Interface (eth0) → External Network

The key component here is docker0 (the bridge). Docker automatically creates a bridge network for containers.


What is a Bridge Network in Docker?

  • Container Communication: Containers on the same bridge network can communicate with each other using container names.
  • Host Isolation: The bridge network provides network isolation between the host and the containers.

Let’s verify if the bridge is created, whether the containers are connected to the same bridge, and explore the bridge details.


1. Check the Network List


1
docker network ls

5-3

As shown above, the created containers are part of the DRIVER(bridge) network.


2. Bridge Network Details


1
docker network inspect bridge
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[
    {
        "Name": "bridge",
        "Id": "7d3d8d77186a1f2dd28027ac25a178c87d0d432ecab2852b78086f68b6301696",
        "Created": "2024-11-29T01:57:46.973940286Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

The Driver is bridge, and the Gateway is 172.17.0.1. This explains why 172.17.0.1 works. The bridge enables communication between containers, and its gateway address is 172.17.0.1.


3. Why does host.docker.internal work?
  • host.docker.internal is a DNS name provided by Docker to access the host machine.
  • It maps the host machine’s IP address, allowing containers to reference services running on the host.

You can test this by pinging host.docker.internal from within a container:

1
2
docker exec -it nestjs-app sh
ping host.docker.internal

5-4

It maps to 192.168.65.254, which explains why setting the DB_HOST to 192.168.65.254 also works.


Conclusion

Today, we explored container connectivity in Docker. By diving deeper into this topic, we gained a better understanding of Docker’s structure and communication principles. While there are still areas I need to study further, this is a step in the right direction.

I hope this post was helpful to you.

Thank you for reading, and happy blogging! 🚀

References

This post is licensed under CC BY 4.0 by the author.