Dockerhosts filemacOScontainerslocal development

Using Hosts Files for Docker Development on Mac

Learn how to configure hosts files for Docker, docker-compose, and container networking. Map container services to local domains and streamline your Docker development workflow.

L

Locahl Team

Β·8 min read

Docker has revolutionized local development by providing isolated, reproducible environments. However, accessing your containers via custom domain names requires careful coordination between Docker networking and your Mac's hosts file. This guide will show you how to seamlessly integrate hosts file management with Docker, docker-compose, and container networking.

Understanding Docker Networking Basics

Before diving into hosts file configuration, it's essential to understand how Docker networking works on macOS.

Docker Desktop Networking Architecture

Docker Desktop on Mac runs containers inside a Linux VM. When you map ports using -p or ports: in docker-compose, Docker creates a bridge between the container's network and your Mac's localhost.

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"  # Host:Container

This means:

  • Port 8080 on your Mac maps to port 80 in the container
  • You can access it via localhost:8080 or 127.0.0.1:8080
  • To use a custom domain, add a hosts file entry pointing to 127.0.0.1

Container-to-Container Communication

Containers within the same Docker network can communicate using service names defined in docker-compose.yml. This doesn't require hosts file modifications:

services:
  web:
    image: nginx:alpine
    depends_on:
      - api
  
  api:
    image: node:18
    expose:
      - "3000"

The web container can reach the API at http://api:3000 without any hosts file configuration.

Simplify your hosts file management

Locahl lets you manage your hosts file visually, without touching the terminal. Automatic DNS flush, multiple environments, and backups included.

Setting Up Custom Domains for Docker Services

Basic Hosts File Configuration

The simplest approach is to map each Docker service to a custom domain:

# /etc/hosts
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
127.0.0.1    admin.docker.test

Then in your docker-compose.yml:

version: '3.8'
services:
  api:
    image: node:18
    ports:
      - "3001:3000"
  
  frontend:
    image: nginx:alpine
    ports:
      - "3002:80"
  
  admin:
    image: nginx:alpine
    ports:
      - "3003:80"

Access your services at:

  • http://api.docker.test:3001
  • http://frontend.docker.test:3002
  • http://admin.docker.test:3003

Using Standard Ports with Multiple Services

If you prefer standard ports (80, 443), you'll need to run only one service per port. Use different domains:

# /etc/hosts
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
services:
  api:
    image: node:18
    ports:
      - "80:3000"  # Access via api.docker.test:80
  
  frontend:
    image: nginx:alpine
    ports:
      - "8080:80"  # Different port for frontend

Wildcard Domains for Subdomains

For applications with dynamic subdomains, use wildcard DNS with dnsmasq:

# Install dnsmasq
brew install dnsmasq

# Configure wildcard for .docker.test
echo "address=/.docker.test/127.0.0.1" >> /usr/local/etc/dnsmasq.conf

# Create resolver
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/docker.test

# Start dnsmasq
sudo brew services start dnsmasq

Now any *.docker.test domain automatically resolves to localhost!

Docker Compose Multi-Service Architecture

Microservices Setup

For complex applications with multiple services:

version: '3.8'
services:
  # Backend API
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://db:5432/myapp
    depends_on:
      - db
  
  # Frontend Application
  frontend:
    build: ./frontend
    ports:
      - "3001:3000"
    environment:
      - API_URL=http://api:3000
  
  # Admin Panel
  admin:
    build: ./admin
    ports:
      - "3002:3000"
  
  # Database
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
  
  # Redis Cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Hosts file configuration:

# /etc/hosts
# Docker Services
127.0.0.1    api.docker.test
127.0.0.1    frontend.docker.test
127.0.0.1    admin.docker.test

Service Discovery Within Docker

Containers discover each other using service names. The frontend container can call the API at http://api:3000 because Docker's internal DNS resolves api to the container's IP.

For external access (from your Mac), use the hosts file entries and mapped ports.

Advanced Docker Networking Patterns

Custom Docker Networks

Create isolated networks for different environments:

version: '3.8'
networks:
  frontend_network:
    driver: bridge
  backend_network:
    driver: bridge

services:
  frontend:
    image: nginx:alpine
    networks:
      - frontend_network
    ports:
      - "80:80"
  
  api:
    image: node:18
    networks:
      - backend_network
      - frontend_network
    ports:
      - "3000:3000"

The api service is accessible from both networks, while frontend only sees the API through the shared network.

External Networks

Connect containers to existing networks:

services:
  web:
    image: nginx:alpine
    networks:
      - existing_network

networks:
  existing_network:
    external: true

Host Network Mode (Linux Only)

On Linux, you can use host networking mode. On macOS, this isn't directly supported, but you can achieve similar results with port mapping.

Port Management Strategies

Avoiding Port Conflicts

When running multiple Docker projects, port conflicts are common. Strategies:

1. Use Different Port Ranges

# Project A
services:
  web:
    ports:
      - "8000:80"

# Project B  
services:
  web:
    ports:
      - "8001:80"

2. Use Environment Variables

services:
  web:
    ports:
      - "\$\{WEB_PORT:-8080}:80"
# .env file
WEB_PORT=9000

3. Dynamic Port Assignment

services:
  web:
    ports:
      - "0:80"  # Docker assigns random port

Check assigned port: docker ps or docker-compose ps

Standard Ports with Reverse Proxy

Use a reverse proxy (Traefik, Nginx) to route based on domain names:

version: '3.8'
services:
  traefik:
    image: traefik:v2.10
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
  
  api:
    image: node:18
    labels:
      - "traefik.http.routers.api.rule=Host(`api.docker.test`)"
      - "traefik.http.services.api.loadbalancer.server.port=3000"
  
  frontend:
    image: nginx:alpine
    labels:
      - "traefik.http.routers.frontend.rule=Host(`frontend.docker.test`)"

With hosts file entries, all services accessible on port 80 via their domains.

Docker and Local HTTPS

Generating SSL Certificates for Docker Services

Use mkcert to create trusted certificates:

# Install mkcert
brew install mkcert
mkcert -install

# Create certificate for Docker services
mkcert api.docker.test frontend.docker.test "*.docker.test"

Configuring HTTPS in Docker

services:
  nginx:
    image: nginx:alpine
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./api.docker.test.pem:/etc/nginx/ssl/cert.pem
      - ./api.docker.test-key.pem:/etc/nginx/ssl/key.pem

Traefik with Automatic HTTPS

Traefik can automatically handle HTTPS:

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./certs:/certs

Organizing Hosts File Entries for Docker

Project-Based Organization

Group entries by project:

# ===================
# DOCKER PROJECT: E-commerce Platform
# ===================
127.0.0.1    shop.docker.test
127.0.0.1    api.shop.docker.test
127.0.0.1    admin.shop.docker.test

# ===================
# DOCKER PROJECT: Blog Platform
# ===================
127.0.0.1    blog.docker.test
127.0.0.1    cms.blog.docker.test

Environment-Based Organization

Separate by environment:

# ===================
# DOCKER: Development
# ===================
127.0.0.1    dev-api.docker.test
127.0.0.1    dev-frontend.docker.test

# ===================
# DOCKER: Staging
# ===================
127.0.0.1    staging-api.docker.test
127.0.0.1    staging-frontend.docker.test

Docker Compose Override Patterns

Development Overrides

Use docker-compose.override.yml for local development:

# docker-compose.yml (base)
version: '3.8'
services:
  api:
    image: node:18
    ports:
      - "3000:3000"

# docker-compose.override.yml (local, gitignored)
version: '3.8'
services:
  api:
    volumes:
      - ./src:/app/src  # Hot reload
    environment:
      - NODE_ENV=development

Multiple Compose Files

# Development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# Production-like
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

Troubleshooting Docker Hosts File Issues

Containers Not Accessible via Custom Domain

Problem: Domain resolves but connection refused.

Solutions: 1. Verify port mapping: docker ps shows 0.0.0.0:PORT->... 2. Check container is running: docker-compose ps 3. Verify hosts file entry: ping api.docker.test should resolve to 127.0.0.1 4. Check firewall settings

Port Already in Use

Problem: Error: bind: address already in use

Solutions: 1. Find process using port: lsof -i :8080 2. Stop conflicting container: docker stop <container> 3. Change port mapping in docker-compose.yml 4. Use different port range

DNS Resolution Issues

Problem: Domain doesn't resolve.

Solutions: 1. Verify hosts file syntax (no extra spaces) 2. Flush DNS cache: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder 3. Check dnsmasq if using wildcards 4. Restart Docker Desktop

Container-to-Container Communication Fails

Problem: Services can't reach each other.

Solutions: 1. Verify services are on same network: docker network inspect <network> 2. Use service names, not localhost 3. Check depends_on ordering 4. Verify expose/ports configuration

Best Practices for Docker Hosts File Management

1. Use Consistent Naming Conventions

# Good: Project-based naming
api.projectname.test
frontend.projectname.test

# Avoid: Generic names
api.test
web.test

2. Document Port Mappings

Include port documentation in README:

## Local Development

- API: http://api.project.test:3000
- Frontend: http://frontend.project.test:8080
- Admin: http://admin.project.test:3001

3. Version Control Hosts File Templates

Create hosts.example in your project:

# hosts.example
127.0.0.1    api.project.test
127.0.0.1    frontend.project.test

4. Use Environment-Specific Domains

# Development
dev-api.project.test

# Staging  
staging-api.project.test

# Local
local-api.project.test

5. Automate Hosts File Updates

Create a script to sync docker-compose services with hosts file:

#!/bin/bash
# sync-docker-hosts.sh

SERVICES=$(docker-compose config --services)
for service in $SERVICES; do
  PORT=$(docker-compose config | grep -A 5 "$service:" | grep -oP 'd+:d+' | head -1 | cut -d: -f1)
  echo "127.0.0.1    $service.docker.test" >> /tmp/docker-hosts
done

Integration with Development Tools

Hot Reload and Volume Mounts

services:
  api:
    build: ./api
    volumes:
      - ./api/src:/app/src  # Hot reload
    ports:
      - "3000:3000"

Access via api.docker.test:3000 with automatic code reloading.

Database Access

services:
  db:
    image: postgres:15
    ports:
      - "5432:5432"  # Expose for external tools

Connect from Mac using localhost:5432 or add db.docker.test to hosts file.

Debugging Tools

services:
  api:
    image: node:18
    ports:
      - "3000:3000"
      - "9229:9229"  # Node.js debugger

Attach debugger via api.docker.test:9229.

Conclusion

Effectively managing hosts files with Docker requires understanding both Docker networking and macOS DNS resolution. By following the patterns outlined in this guide, you can:

  • Map container services to memorable domain names
  • Avoid port conflicts across multiple projects
  • Maintain clean, organized hosts file configurations
  • Streamline your Docker development workflow

Remember to use .test domains to avoid conflicts, document your port mappings, and leverage tools like Locahl to manage your hosts file entries efficiently. With proper configuration, Docker and hosts files work together seamlessly to create a productive local development environment.

For teams working with Docker, consider using Locahl (€9.99) to share hosts file configurations, maintain consistency across environments, and eliminate the manual editing overhead. Locahl makes it easy to export, import, and sync hosts file entries across your entire team.

Also readHow to edit the hosts file on Mac
Also readComplete local development guide
Share this article
Available for macOS

Ready to simplify your workflow?

Stop wasting time with the terminal. Locahl lets you manage your hosts file in a few clicks, with automatic validation and no risk of errors.

  • Intuitive visual interface
  • Automatic DNS flush
  • Multi-environment management
  • Automatic backups
  • JSON Import/Export
Get Locahl - €9.99One-time payment, no subscription

Reader Reviews

4.7β˜…(3 reviews)
James R.
β˜…β˜…β˜…β˜…β˜…

"Finally, a clear guide on Docker and hosts files! The docker-compose networking section was exactly what I needed."

February 6, 2026

Sarah M.
β˜…β˜…β˜…β˜…β˜…

"The service mapping examples saved me hours of trial and error. Great practical advice for Docker workflows."

February 6, 2026

David L.
β˜…β˜…β˜…β˜…β˜…

"Very comprehensive. Would have liked more on Docker Desktop networking specifics, but overall excellent guide."

February 6, 2026

Frequently Asked Questions

How do I access Docker containers via custom domains?

Map container ports to host ports in docker-compose.yml, then add entries to your hosts file pointing to 127.0.0.1. Use .test domains to avoid conflicts.

Do I need to modify hosts file for each Docker container?

Only if you want custom domain names. Containers can access each other by service name within the same Docker network without hosts file modifications.

How do Docker networks interact with the hosts file?

The hosts file only affects your Mac's DNS resolution. Docker containers use their own internal DNS and networks. Map host ports to access containers via hosts file entries.

Can I use .local domains with Docker on Mac?

Not recommended. .local domains conflict with macOS Bonjour. Use .test or .localhost instead for better performance and compatibility.

How do I share Docker hosts file configurations with my team?

Export your hosts file entries and include them in your project documentation. Tools like Locahl make it easy to share and sync hosts file configurations across team members.

Related Articles

11 min read
LaravelWordPresslocal development

Hosts File Setup for Laravel/WordPress Local Development

Complete guide to configuring hosts files for Laravel Valet, Herd, and WordPress local development. Learn custom domains (.test, .local), multisite configurations, and best practices.

L

Locahl Team

5 min read
hosts filemacOStutorial

Edit the hosts file on Mac: Terminal vs GUI (2026)

How to edit /etc/hosts on macOS without errors? Terminal (sudo nano) vs GUI comparison. Fix permission denied and DNS cache issues in 2 minutes.

L

Locahl Team