Skip to content

tbreuss/local-dev

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Local Development Environment

A lightweight local development environment for macOS using dnsmasq, Docker, and Traefik to enable seamless development of multiple services with API interdependencies.

Table of Contents

Goals

  • Multi-Service Support: Facilitate local development involving multiple Docker services with complex API dependencies.
  • Unified DNS: Use *.test domain names consistently on both the macOS host and inside Docker containers.
  • Routing: Support for both HTTP and TCP routing.
  • HTTPS Ready: HTTPS support (note: currently requires ignoring browser warnings for self-signed certificates).
  • Zero Maintenance: Eliminate the need to manually edit /etc/hosts.

Prerequisites

This setup was tested with the following versions but should be compatible with earlier releases:

  • OS: macOS Tahoe (26.0)
  • Package Manager: Homebrew (4.6)
  • DNS Server: dnsmasq (2.91)
  • Container Engine: Docker Desktop for Mac (4.48)

Solution

The setup consists of three main steps:

  1. Create a persistent loopback interface for IP 10.254.254.254.
  2. Configure dnsmasq to route *.test domains to this IP.
  3. Launch Traefik and other containers via Docker Compose.

1. Create a Persistent Loopback Interface on macOS

We will create a launchd daemon to assign an additional IPv4 address (10.254.254.254) to the loopback interface (lo0), ensuring it persists after reboots.

Create the Launch Daemon:

cat << EOF | sudo tee -a /Library/LaunchDaemons/com.github.tbreuss.local-dev.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.github.tbreuss.local-dev</string>
    <key>ProgramArguments</key>
    <array>
        <string>/sbin/ifconfig</string>
        <string>lo0</string>
        <string>alias</string>
        <string>10.254.254.254</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
  </dict>
</plist>
EOF

Load the Service:

sudo launchctl load /Library/LaunchDaemons/com.github.tbreuss.local-dev.plist

Verify the Service:

sudo launchctl list | grep local-dev
# Expected output: -	0	com.github.tbreuss.local-dev

Check the Interface (after a reboot):

ifconfig lo0
# Look for: inet 10.254.254.254 netmask 0xff000000

2. Install and Configure dnsmasq

Install dnsmasq via Homebrew:

brew update
brew install dnsmasq
sudo brew services start dnsmasq

Configure dnsmasq:

Open /usr/local/etc/dnsmasq.conf and ensure the following line is present (uncommented):

conf-dir=/usr/local/etc/dnsmasq.d,*.conf

Create a custom configuration file:

mkdir -p /usr/local/etc/dnsmasq.d
touch /usr/local/etc/dnsmasq.d/development.conf

Add the routing rule to direct all *.test domains to our loopback IP:

address=/.test/10.254.254.254

Configure macOS Resolver:

Create a resolver file for the .test TLD so macOS knows to query dnsmasq for these domains:

sudo mkdir -p /etc/resolver
echo "nameserver 10.254.254.254" | sudo tee /etc/resolver/test

Verify the Setup:

Check that the resolver is registered:

scutil --dns
# Look for a section "resolver #X" where domain is "test" and nameserver is "10.254.254.254"

Test DNS resolution:

# Ensure external domains still work
ping -c 1 google.com

# Test local resolution
ping -c 1 mysite.test
ping -c 1 my.other.site.test

3. Launch Traefik and Containers via Docker Compose

Install Docker Desktop (if not already installed): Download Docker Desktop for Mac

Clone the Project:

git clone https://github.com/tbreuss/local-dev.git
cd local-dev

Start Services:

docker-compose up

Verification:

  1. Open http://whoami.test in your browser. You should see output similar to:

    Hostname: eb7f1da188d7
    IP: 127.0.0.1
    IP: 172.18.0.5
    RemoteAddr: 172.18.0.2:45232
    GET / HTTP/1.1
    Host: whoami.test
    ...
    X-Forwarded-Host: whoami.test
    X-Forwarded-Proto: http
    
  2. Open https://whoami.test. The browser will likely show a certificate warning (e.g., NET::ERR_CERT_AUTHORITY_INVALID). You can proceed past this warning. The output should be similar to the HTTP version.

  3. Test Inter-Container Communication: Execute a request from one container to another (e.g., from adminer):

    docker-compose exec adminer curl http://whoami.test

    For HTTPS (using --insecure to skip cert validation):

    docker-compose exec adminer curl --insecure https://whoami.test

Important: Always verify that DNS resolution and container routing still work after rebooting your Mac.

Included Docker Images

At the time of writing, this repository includes configurations for the following images:

References

Special thanks to the authors of the following guides which inspired this setup:

About

Lightweight web development environment for macOS Tahoe using dnsmasq, Docker, Docker-Compose and Traefik

Topics

Resources

Stars

Watchers

Forks

Contributors