Philip Miglinci  Philip Miglinci   docker alpine-linux unbound dns

Host your own 7mb DNS Server with Docker, Alpine Linux and Unbound

Docker image

$ docker images
REPOSITORY    VIRTUAL SIZE
dns           7.497 MB

As we are currently bootstrapping a mobile App on a minimal budget we want to do as much as possible on your own infrastructure (a 4 year old laptop).

We have a few hundred users now enjoining our app on a regular basis. Also a second developer joined the team. Now it's definitely time for a dedicated development environment.

There is no money for a development environment

A founded startup would just create some instances on AWS, or assign some IP addresses to a server and they are ready to go. We can't do that.

As we are hosting at home and only have one IP addr available we relay on our internal subnet and a proxy server which redirects traffic accordingly. To simulate this behavior in our home network we have to create custom DNS rules to match servernames to internal IP addresses.

Docker, Alpine and Unbound let you create a minimal DNS in minutes.

Your dockerfile will look something like this:

FROM alpine:3.3

RUN apk add --update unbound ; \
	rm -rf /var/cache/apk/* ;

COPY unbound.conf /etc/unbound/unbound.conf
COPY root.hints /var/unbound/etc/root.hints
COPY root.key /var/unbound/etc/root.key

RUN unbound-checkconf

CMD ["unbound"]

The root.hints file can be downloaded here.

The root.key signs the top level DNS Servers downloaded above:

. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5

In our unbnound.conf you can now create custom DNS Entries e.g. A-Records:

server:
  interface: 0.0.0.0
  verbosity: 1
  do-daemonize: no
  access-control: 0.0.0.0/0 allow
  do-ip4: yes
  do-ip6: no
  do-udp: yes
  do-tcp: no
  hide-identity: yes
  hide-version: yes
  harden-glue: yes
  harden-dnssec-stripped: yes
  use-caps-for-id: yes
  cache-min-ttl: 3600
  cache-max-ttl: 86400
  prefetch: yes
  num-threads: 4
  msg-cache-slabs: 8
  rrset-cache-slabs: 8
  infra-cache-slabs: 8
  key-cache-slabs: 8
  rrset-cache-size: 256m
  msg-cache-size: 128m
  so-rcvbuf: 1m
  private-address: 192.168.1.0/16
  unwanted-reply-threshold: 10000
  do-not-query-localhost: no
  val-clean-additional: yes

  local-zone: "pmig.at." static
  local-data: "pmig.at.  IN A 192.168.1.201"

forward-zone:
  name: "."
  forward-addr: 195.34.133.10
  forward-addr: 213.33.99.70
  forward-addr: 8.8.8.8
  forward-addr: 8.8.4.4

It's possible to define a local-zone and set A records accordingly. If your address is not in your local zone you will just ask the next DNS Server. In our case we just use our ISP's DNS and the Google DNS if our ISP fails.

You just need to ensure you just 53/udp to your docker host and configure it in your router which servers you the internal IP's.

Ready! You can setup as many docker development servers in your local network now!


If you have any questions, just hit me up on Twitter:

How our own DNS server helps us bootstrapping our app. #docker #alpinelinux #unbound #dns #startup #bootstrap

@pmigat/status/688339334706130944

— Philip Miglinci (@pmigat)