Configure DNS server using docker to handle requests from sub-domain
Update
It is not recommended if using a recursive DNS server for public service. Dnsmasq, however, only supports recursive. Using dnsmasq in public can make your server vulnerable to DDOS attacks.
Why Dnsmasq
After adding too many DNS records to my Cloudflare account, I find it necessary to find a way to reduce the record. However, using wildcards is only available for pro-plan users. So I decided to deploy my own DNS server.
Then I chose to deploy dnsmasq, a simple DNS server, on docker.
Configure dnsmasq
Docker Compose
The docker-compose.yml looks like this:
version: '3.6'
services:
dnsmasq:
image: andyshinn/dnsmasq
restart: always
container_name: 'dnsmasq'
network_mode: host
cap_add:
- NET_ADMIN
volumes:
- ./data/dnsmasq.conf:/etc/dnsmasq.conf
- ./data/dnsmasqhosts:/etc/dnsmasqhosts
- ./data/resolv.dnsmasq.conf:/etc/resolv.dnsmasq.conf
Together with this file, we create a folder called data, which contains the configuration file of dnsmasq.
dnsmasq. conf
# setting upstream dns server
resolv-file=/etc/resolv.dnsmasq.conf
addn-hosts=/etc/dnsmasqhosts
strict-order
# both local address and public address
listen-address=127.0.0.1,202.182.*.*
# upstream dns server
server=108.61.*.*
# prevent dns hijacking
bogus-nxdomain=108.61.*.*
address=/*.*.example.com/202.182.*.*
resolv.dnsmasq.conf
nameserver 108.61.*.*
After setting up, use docker-compose up
to start the server. Which may get an error like this
docker: Error response from daemon: failed to create endpoint DNS-server on network bridge: Error starting userland proxy: listen tcp 0.0.0.0:53: bind: address already in use.
Using netstat -ltnp
, I found the port was used by systemd-resolved
, so I stopped the server and retried.
sudo systemctl stop systemd-resolved
This time, dnsmasq was successfully started
Systemd-resolved
However, stopping systemd-resolved may also stop your network. So it is necessary to configure systemd-resolved not occupying the port.
Editing the following files and replace them with this:
/etc/systemd/resolved.conf
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See resolved.conf(5) for details
[Resolve]
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See resolved.conf(5) for details
[Resolve]
#DNS=
#FallbackDNS=
#Domains=
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=yes
DNSStubListener=no
#ReadEtcHosts=yes
/etc/resolve.conf
Before editing this file, you need to remove and create it again to disable the systemd to create a symlink on it.
nameserver 127.0.0.1
nameserver 108.61.*.*
Testing DNS server on local
Now you may use dig
to test the server
$ dig google.com
; <<>> DiG 9.11.5-P1-1ubuntu2.3-Ubuntu <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44353
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 161 IN A 172.217.31.174
;; Query time: 0 msec
;; SERVER: 108.61.*.*#53(108.61.*.*)
;; WHEN: Tue Sep 24 17:33:49 UTC 2019
;; MSG SIZE rcvd: 55
$ dig *.*.example.com
; <<>> DiG 9.11.5-P1-1ubuntu2.3-Ubuntu <<>> *.*.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26535
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;*.*.example.com. IN A
;; ANSWER SECTION:
*.*.example.com. 30 IN A 202.182.*.*
;; Query time: 9 msec
;; SERVER: 108.61.*.*#53(108.61.*.*)
;; WHEN: Tue Sep 24 17:35:10 UTC 2019
;; MSG SIZE rcvd: 82
All the requests are successful.
Adding NS record to DNS provider
However, on another machine, the second query request cannot be processed and will return SERVFAIL
. To let other machines be able to use our newly established DNS server, we need to add an NS record to it. In this example, I will use Cloudflare.
Firstly, adding an A record pointed to the server.
Second, add an NS record of your sub-domain which you want your custom DNS server to handle.
Now the server will be able to handle requests from other machines.
References
[0] https://blog.csainty.com/2016/09/running-dnsmasq-in-docker.html
[1] https://www.digitalocean.com/community/questions/dnsmasq-and-local-docker-container
[2] https://www.coderli.com/config-dnsmasq-using-docker/
[3] https://medium.com/@niktrix/getting-rid-of-systemd-resolved-consuming-port-53-605f0234f32f
[4] https://qiita.com/bmj0114/items/9c24d863bcab1a634503
[5] https://support.rackspace.com/how-to/using-dig-to-query-nameservers/
[6] https://www.ilanni.com/?p=10624