A lightweight local development environment for macOS using dnsmasq, Docker, and Traefik to enable seamless development of multiple services with API interdependencies.
- Multi-Service Support: Facilitate local development involving multiple Docker services with complex API dependencies.
- Unified DNS: Use
*.testdomain 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.
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)
The setup consists of three main steps:
- Create a persistent loopback interface for IP
10.254.254.254. - Configure dnsmasq to route
*.testdomains to this IP. - Launch Traefik and other containers via Docker Compose.
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>
EOFLoad the Service:
sudo launchctl load /Library/LaunchDaemons/com.github.tbreuss.local-dev.plistVerify the Service:
sudo launchctl list | grep local-dev
# Expected output: - 0 com.github.tbreuss.local-devCheck the Interface (after a reboot):
ifconfig lo0
# Look for: inet 10.254.254.254 netmask 0xff000000Install dnsmasq via Homebrew:
brew update
brew install dnsmasq
sudo brew services start dnsmasqConfigure dnsmasq:
Open /usr/local/etc/dnsmasq.conf and ensure the following line is present (uncommented):
conf-dir=/usr/local/etc/dnsmasq.d,*.confCreate a custom configuration file:
mkdir -p /usr/local/etc/dnsmasq.d
touch /usr/local/etc/dnsmasq.d/development.confAdd the routing rule to direct all *.test domains to our loopback IP:
address=/.test/10.254.254.254Configure 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/testVerify 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.testInstall 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-devStart Services:
docker-compose upVerification:
-
Open
http://whoami.testin 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 -
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. -
Test Inter-Container Communication: Execute a request from one container to another (e.g., from
adminer):docker-compose exec adminer curl http://whoami.testFor HTTPS (using
--insecureto 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.
At the time of writing, this repository includes configurations for the following images:
Special thanks to the authors of the following guides which inspired this setup: