Skip to content

Instantly share code, notes, and snippets.

@tboerger
Last active September 13, 2019 09:08
Show Gist options
  • Save tboerger/dd93239d19908ec1eed13d6e644fab72 to your computer and use it in GitHub Desktop.
Save tboerger/dd93239d19908ec1eed13d6e644fab72 to your computer and use it in GitHub Desktop.
macOS Environment

Within this guide I will guide you step by step throu a setup of a local DNS setup to resolve local services as well as services running within Docker. Within this guide I will use Homebrew to install the required services, please follow the official instructions to install it.

We will use .lan as toplevel domain for local name resolution, all our services will be available by this name. To get it working on nearly all environments I will also attach a private IP to our loopback network interface where I have choosen 10.254.254.254, this is required to get the host and the Docker services resolving the same names.

Loopback

First I will make sure that our private IP gets assigned to our loopback interface, with this service it will also be set up again after rebooting the host. You can define as many aliases as you want, but for this guide a single IP should be totally fine.

cat << EOF | sudo tee /Library/LaunchDaemons/de.webhippie.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>de.webhippie.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

To keep the IP alias persistant accros reboots I need to load this defined .plist file via launchctl, otherwise the IP is lost after a reboot.

sudo launchctl load /Library/LaunchDaemons/de.webhippie.loopback1.plist

You can check if the service is loaded properly by checking it with launchctl:

sudo launchctl list | grep de.webhippie

Dnsmasq

For the local name resolution I will install dnsmasq which is a simple local nameserver, it also provides more features, but I won't need them for our setup.

brew install dnsmasq

Next I need to add our local domain to the dnsmasq configuration file. You can simply echo the required changes into the configuration files.

echo "conf-dir=/usr/local/etc/dnsmasq.d/,*.conf" | tee -a /usr/local/etc/dnsmasq.conf
echo "address=/lan/10.254.254.254" | tee /usr/local/etc/dnsmasq.d/lan.conf

To finally start the service you can simply launch it with Homebrew, this will wrap the macOS service start scripts and will also start the service in the background after a reboot.

sudo brew services start dnsmasq

You can quite simple confirm that the name resolution works as expected just by executing dig @127.0.0.1 foo.lan, this should result in a response like:

; <<>> DiG 9.10.6 <<>> @127.0.0.1 foo.lan
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4845
;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;foo.lan.                       IN      A

;; ANSWER SECTION:
foo.lan.                0       IN      A       10.254.254.254

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Sep 13 09:47:08 CEST 2019
;; MSG SIZE  rcvd: 52

Resolver

To automatically resolve all .lan domains to our previously installed dnsmasq I also got to define a local resolver, just execute the following command to properly resolve local names.

echo "nameserver 127.0.0.1" | sudo tee -a /etc/resolver/lan

You can confirm that the resolver is configured properly by simply executing scutil --dns, this should show the newly defined .lan resolver similar to this:

resolver #8
  domain   : lan
  nameserver[0] : 127.0.0.1
  flags    : Request A records
  reach    : 0x00000002 (Reachable)

Docker

To get Docker fo Mac installed you can simply install it via Homebrew, just execute the following command to get it. After the successfull installation you got to initially start it once, press ⌘ + Space and enter docker, press Enter.

brew cask install docker

To confirm that Docker is working as expected you can execute docker info to see if it prints some version information.

Certificate

As usual there are quite often the scenarios where you want to run your local services with SSL, for that case I am using mkcert, which generates certificates for you and adds them automatically to your browser. But first I need to install it.

brew install mkcert nss

After installing the required packages you got to generate and install the custom root certificate by executing:

mkcert -install

Finally I will generate our wildcard certificate for our defined .lan toplevel domain. You can store it whereever you like, I will just put it into my local ownCloud folder:

mkdir -p ~/ownCloud/Documents/Certificates
cd ~/ownCloud/Documents/Certificates

mkcert \*.lan

You should have two files generated now, they are named _wildcard.lan-key.pem and _wildcard.lan.pem.

Traefik

To have a proper reverse proxy for our Docker services I am using Traefik which is a great piece of software.

docker run -d \
  --restart always \
  --name traefik \
  --publish :80:80 \
  --publish 443:443 \
  --volume ${HOME}/ownCloud/Documents/Certificates:/etc/certs \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --label traefik.port=8000 \
  traefik:1.7 \
  --traefiklog \
  --accesslog \
  --api \
  --docker \
  --docker.domain=lan \
  --defaultentrypoints=http \
  --defaultentrypoints=https \
  --entrypoints='Name:traefik Address::8000' \
  --entrypoints='Name:http Address::80' \
  --entrypoints='Name:https Address::443 TLS:/etc/certs/_wildcard.lan.pem,/etc/certs/_wildcard.lan-key.pem'

To confirm that caddy is working as expected you can simply use curl or your browser and access http://traefik.lan, this should show the traefik dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment