tbreuss / local-dev

Lightweight web development environment for MacOS Monterey using dnsmasq, Docker, Docker-Compose and Traefik
27 stars 1 forks source link
dnsmasq docker docker-compose hacktoberfest homebrew local-development macos traefik

LOCAL-DEV

This is my lightweight local development environment using dnsmasq, Docker, and Traefik running on macOS Monterey.

Goals

Prerequisites

This is my current set up:

The instructions should also work with older versions.

Solution

  1. Create persistent loopback interface for IP 10.254.254.254
  2. Install dnsmasq using IP 10.254.254.254 for nameserver and address target
  3. Launch Traefik and other containers using Docker Compose

1. Create persistent loopback interface in macOS

Create a "launchd" daemon that configures an additional IPv4 address.

cat << EOF | sudo tee -a /Library/LaunchDaemons/ch.tebe.loopback1.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>ch.tebe.loopback1</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

Launch service:

sudo launchctl load /Library/LaunchDaemons/ch.tebe.loopback1.plist

Make sure it works:

LaunchDaemons % sudo launchctl list | grep ch.tebe
-   0   ch.tebe.loopback1

Restart Mac and check ifconfig:

ifconfig lo0
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
    inet 127.0.0.1 netmask 0xff000000
    inet6 ::1 prefixlen 128
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
    inet 10.254.254.254 netmask 0xff000000
    nd6 options=201<PERFORMNUD,DAD>

2. Install and configure dnsmasq

Install dnsmasq using Homebrew:

brew update # Always update Homebrew and the formulae first
brew install dnsmasq

Start dnsmasq service:

sudo brew services start dnsmasq

Open /usr/local/etc/dnsmasq.conf and add/uncomment the following line:

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

Create custom conf file:

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

Add routing rule for *.test domain names:

address=/.test/10.254.254.254 

Add custom resolver:

sudo mkdir /etc/resolver

Create a file /etc/resolver/test for the *.test domain names and add this line:

nameserver 10.254.254.254

Check that the resolver is registered.

scutil --dns
...
resolver #8
  domain   : test
  nameserver[0] : 10.254.254.254
  flags    : Request A records
  reach    : 0x00030002 (Reachable,Local Address,Directly Reachable Address)
...  

Check the dnsmasq setup:

ping -c 1 google.com # Make sure you can still access the outside world! 
ping -c 1 mysite.test
ping -c 1 my.other.site.test

3. Launch Traefik and other containers using Docker Compose

Install Docker Desktop:

https://www.docker.com/products/docker-desktop

Clone project from Github:

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

Start services using Docker Compose:

cd local-dev
docker-compose up

Check that everything works as expected.

Open http://whoami.test with your favorite browser. You should see something like:

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
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Dnt: 1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: whoami.test
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 73db93d4c8e8
X-Real-Ip: 172.18.0.1

Now, open https://whoami.test with your favorite browser. The browser displays a NET::ERR_CERT_AUTHORITY_INVALID warning or similar, but lets you proceed to the website if you choose to. You should see a similar output like above.

Make a cURL call from one docker container to another:

docker-compose exec adminer curl http://whoami.test
Hostname: eb7f1da188d7
IP: 127.0.0.1
IP: 172.18.0.5
RemoteAddr: 172.18.0.2:45238
GET / HTTP/1.1
Host: whoami.test
User-Agent: curl/7.80.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 172.18.0.1
X-Forwarded-Host: whoami.test
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 73db93d4c8e8
X-Real-Ip: 172.18.0.1

Try the same using https:

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

You should see a similar output like above.

Don't forget to check the same after rebooting your Mac.

Included Docker Images

At the time of writing this repo includes configs for the following Docker images:

Links

Thanks to the authors of these helpful blog posts: