Why 127.0.0.1 Doesn’t Reach Local Redis in Docker

20 Oct 2025 • 5 minutes

Junwen Feng
Engineer

Scenario Description

At InsForge, our cloud backend is built on OpenResty as a reverse proxy, paired with a Redis Cluster for service discovery. This setup lets us dynamically route developer API requests based on real-time project information.

Recently, we wanted to replicate this setup in a smaller environment for local experiments. To keep things simple, Redis and OpenResty each run in their own Docker Compose project: one serving as the storage backend and the other acting as the reverse proxy.

The project structure looks like this:


Below are the example configurations for each service.

Redis


OpenResty


The Problem: 127.0.0.1 Cannot Connect to Redis

In OpenResty’s Lua code, we attempt to connect to Redis:


But when this code runs, the logs show an unexpected error:


This is unexpected. Redis has already been mapped to the host port 6379 using -p 6379:6379, which makes it accessible from the host machine. However, when accessed from within another container, the connection fails.

Understanding Docker Networking

The Principle of Docker Network Isolation

To understand this behavior, we need to look at how Docker manages container networking. Every container runs in its own virtual network stack, which provides:

  • Its own network interfaces
  • Its own IP address
  • Its own routing table
  • Its own port space

When a container starts, Docker automatically creates this virtual network namespace. Within this environment:

  • 127.0.0.1 (localhost) refers only to the container itself, not the host
  • Each container receives a private IP address, typically within the subnet of the docker0 bridge
  • Port mappings such as -p 6379:6379 apply only to traffic between the host and the container, not between containers

Network Architecture Diagram


Why Doesn’t 127.0.0.1 Work?

When the OpenResty container attempts to connect to 127.0.0.1:6379, the connection is handled entirely within its own namespace.

  1. The request is scoped to the OpenResty container’s local network stack.
  2. Inside that namespace, 127.0.0.1 resolves to the OpenResty container itself.
  3. Redis is running in a different container, with a separate namespace.
  4. Therefore, no process is listening on port 6379 inside OpenResty, resulting in a “connection refused” error.

Although Redis’s port is mapped to the host, this mapping is not visible inside other containers. Each container is isolated by design, so they cannot reach each other through 127.0.0.1 unless explicitly connected to a shared network.

Correct Connection Methods

There are several ways to connect containers so that OpenResty can successfully reach Redis. Each approach depends on your environment and use case.

Option 1: Use the Host Gateway IP

Each Docker network defines a gateway IP, usually the first address in the subnet. For the default bridge network, this is often 172.17.0.1.

To find the gateway IP inside the container:


Alternatively, you can check /etc/hosts:


Once you have the gateway IP, update the Lua connection code as follows:


The gateway IP acts as a bridge between the container and the host. Containers can use this address to access host-exposed ports, such as Redis mapped with -p 6379:6379.

Option 2: Use host.docker.internal (Recommended for Development)

Docker Desktop provides a special DNS name host.docker.internal, which resolves to the host IP. This allows containers to communicate with services exposed on the host.


This approach works well for local development and testing because it requires no additional network setup.

Notes:

  • Works by default on Docker Desktop for Mac/Windows
  • On Linux, it must be added manually by including a host entry when starting the container: --add-host=host.docker.internal:host-gateway

This method provides a simple way to reach host-exposed ports without modifying Docker Compose networks. However, it is generally best suited for local development, not production environments.

Option 3: Use a Shared Docker Network (Best Practice)

For long-term maintainability and service-to-service communication, the recommended approach is to connect containers through a shared Docker network.

Start by creating an external network:


Then configure both Docker Compose projects to use this shared network.

Redis docker-compose.yml:


OpenResty docker-compose.yml:


Once both containers are connected to the same network, Docker’s built-in DNS automatically resolves service names. The OpenResty container can connect to Redis using its service name.

Then in Lua:


Using a shared network keeps configuration clean, avoids host-specific dependencies, and ensures reliable communication across environments. This is considered the best practice for production deployments.

How Docker Compose Service Name Resolution Works

When multiple services are defined in the same docker-compose.yml:


The OpenResty container can connect using redis as the hostname because:

1. Docker’s Built-in DNS Server

Each user-defined Docker network includes an internal DNS server, typically located at 127.0.0.11. This server maintains the mapping between service names and container IP addresses.

You can confirm this by checking the container’s resolver configuration:


2. Service Discovery

Docker Compose automatically performs the following for each service:

  • Creates a DNS record for each service name
  • Resolves the name to the container IP
  • Supports round-robin DNS for scaled services

Example:


This means any container in the same Docker network can connect to Redis simply by referencing redis as the hostname.

3. Network Aliases

Docker also supports network aliases, allowing multiple hostnames to resolve to the same container.
Example configuration:


In this configuration, the names redis, redis-master, and cache-server all resolve to the same Redis container. This can be helpful when multiple hostnames are required for compatibility or migration.

4. Cross-Compose Service Discovery

By default, services defined in different Docker Compose projects cannot communicate with each other because each project creates its own isolated network.
To enable cross-project communication, you can use one of the following approaches:

  • Connect both projects to a shared external network (see Option 3)
  • Use the host gateway or port mappings (see Options 1 and 2)

Once both services are attached to the same network, Docker’s internal DNS will resolve all service names within that network, allowing seamless communication between containers across projects.

Best Practice Recommendations

For Development

For local development, the simplest and most reliable approach is to connect all containers through a shared Docker network.


Once the network is created, attach each service to it through its respective Compose file. Containers on the same network can communicate directly using service names, without relying on IP addresses or host mappings.

For Production

In production environments, network design and service discovery should be more structured. Consider the following approaches:

  1. Use Kubernetes for built-in service discovery and orchestration.
  2. Deploy a Service Mesh such as Istio or Linkerd to manage advanced routing, observability, and security.
  3. Integrate dedicated discovery tools like Consul or Etcd for fine-grained control in distributed systems.

These solutions provide better scalability, reliability, and visibility than manual container networking.

Configuration Management

To make the setup more flexible, externalize the Redis connection configuration instead of hardcoding host and port values.

config.lua


In your docker-compose.yml, set the environment variables so each service can load its configuration dynamically:


Summary

Docker network isolation is powered by Linux namespaces, giving each container its own network stack. Key takeaways:

  1. 127.0.0.1 inside a container points to itself, not the host
  2. Port mapping operates on the host, not between containers
  3. Reliable inter-container communication methods include:
    • The host gateway or host.docker.internal for host-level access.
    • A shared Docker network with service-based DNS resolution (recommended).
  4. Docker Compose uses an internal DNS service to automatically resolve service names to container IPs.

Understanding these principles helps prevent connectivity issues and leads to cleaner, more maintainable microservice architectures.