Need custom DNS resolution in containers? Use extra_hosts to add hostname mappings without touching system files!

Basic extra_hosts usage

Add custom host entries to containers:

services:
  app:
    image: myapp
    extra_hosts:
      - "api.local:192.168.1.100"
      - "db.local:192.168.1.101"
      - "cache.local:192.168.1.102"

Inside the container:

docker compose exec app cat /etc/hosts
# 127.0.0.1       localhost
# 192.168.1.100   api.local
# 192.168.1.101   db.local
# 192.168.1.102   cache.local

Dynamic host resolution

Use host machine’s IP dynamically:

services:
  app:
    image: myapp
    extra_hosts:
      - "host.docker.internal:host-gateway"  # Magic value!

This maps to:

  • On Linux: Host’s IP on default bridge
  • On Mac/Windows: Special DNS name to host

Environment-based hosts

Different hosts per environment:

services:
  app:
    image: myapp
    extra_hosts:
      - "api.service:${API_HOST:-127.0.0.1}"
      - "auth.service:${AUTH_HOST:-127.0.0.1}"
      - "cdn.service:${CDN_HOST:-127.0.0.1}"

.env.development:

API_HOST=localhost
AUTH_HOST=localhost
CDN_HOST=localhost

.env.production:

API_HOST=10.0.1.50
AUTH_HOST=10.0.1.51
CDN_HOST=cdn.example.com

Testing against production APIs

Route specific domains to local/mock services:

services:
  app:
    image: myapp
    extra_hosts:
      # Override production APIs
      - "api.example.com:127.0.0.1"
      - "auth.example.com:127.0.0.1"
    ports:
      - "3000:3000"

  # Mock API server
  mock-api:
    image: mockserver
    extra_hosts:
      - "api.example.com:127.0.0.1"
    ports:
      - "80:8080"

Multiple service aliases

Create multiple hostnames for the same IP:

services:
  web:
    image: nginx
    extra_hosts:
      # All pointing to the same service
      - "app.local:172.20.0.5"
      - "www.local:172.20.0.5"
      - "admin.local:172.20.0.5"
      - "api.local:172.20.0.5"

  app:
    image: myapp
    networks:
      default:
        ipv4_address: 172.20.0.5

networks:
  default:
    ipam:
      config:
        - subnet: 172.20.0.0/16

Development with external services

Connect to services outside Docker:

services:
  frontend:
    image: node:18
    working_dir: /app
    volumes:
      - .:/app
    extra_hosts:
      # Local development servers
      - "backend.local:host-gateway"     # Your host machine
      - "database.local:192.168.1.50"    # Another machine
      - "redis.local:192.168.1.51"       # Another machine
    command: npm run dev
    environment:
      API_URL: http://backend.local:8080
      DB_HOST: database.local
      REDIS_HOST: redis.local

Complete example: Microservices testing

services:
  # API Gateway
  gateway:
    image: nginx
    ports:
      - "80:80"
    extra_hosts:
      - "users.service:172.25.0.10"
      - "orders.service:172.25.0.11"
      - "inventory.service:172.25.0.12"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - users
      - orders
      - inventory

  # Microservices
  users:
    image: users-service
    extra_hosts:
      - "auth.provider:${AUTH_SERVER:-host-gateway}"
      - "email.service:${EMAIL_SERVER:-host-gateway}"
    networks:
      default:
        ipv4_address: 172.25.0.10

  orders:
    image: orders-service
    extra_hosts:
      - "users.service:172.25.0.10"
      - "inventory.service:172.25.0.12"
      - "payment.gateway:${PAYMENT_HOST:-sandbox.paypal.com}"
    networks:
      default:
        ipv4_address: 172.25.0.11

  inventory:
    image: inventory-service
    extra_hosts:
      - "warehouse.api:${WAREHOUSE_HOST:-mock-warehouse}"
    networks:
      default:
        ipv4_address: 172.25.0.12

  # Mock external service
  mock-warehouse:
    image: mockserver
    container_name: mock-warehouse

networks:
  default:
    ipam:
      config:
        - subnet: 172.25.0.0/16

Debugging DNS resolution

Test hostname resolution:

services:
  dns-debug:
    image: alpine
    extra_hosts:
      - "test1.local:1.2.3.4"
      - "test2.local:5.6.7.8"
      - "host.machine:host-gateway"
    command: |
      sh -c "
        echo '=== /etc/hosts ==='
        cat /etc/hosts
        echo
        echo '=== DNS Resolution ==='
        nslookup test1.local || echo 'nslookup not available'
        echo
        echo '=== Ping Tests ==='
        ping -c 1 test1.local || true
        ping -c 1 host.machine || true
      "

YAML anchors for shared hosts

Reuse common host mappings:

x-common-hosts: &common-hosts
  - "auth.local:10.0.0.1"
  - "cache.local:10.0.0.2"
  - "db.local:10.0.0.3"

services:
  app1:
    image: app1
    extra_hosts: *common-hosts

  app2:
    image: app2
    extra_hosts:
      <<: *common-hosts
      - "special.local:10.0.0.4"  # Additional host

  app3:
    image: app3
    extra_hosts: *common-hosts

Further reading