Easy to use CoreDNS container with reasonable defaults.
This is based on CoreDNS, and Let's Encrypt (via Lego).
This is useful in the following scenarios:
- you want to run a local DNS server on your LAN (or your laptop) that will forward requests with encryption to an upstream resolver ( like Cloudflare, Quad9, Google, or any other DoT public resolver)
- you want to run your own DNS over TLS (recursive) service
- other stuff
Before running this publicly on the internet, you should think twice though, and make sure you understand the implications.
-
multi-architecture (publishing):
- linux/amd64
- linux/arm64
-
multi-architecture (not publishing anymore)
- linux/386
- linux/arm/v7
- linux/arm/v6
- linux/ppc64le
- linux/s390x
-
hardened:
- image runs read-only
- image runs with no capabilities but NET_BIND_SERVICE, which you could remove if you use unprivileged ports
- process runs as a non-root user, disabled login, no shell
-
lightweight
- based on our slim Debian Bullseye
- simple entrypoint script
- multi-stage build with no installed dependencies for the runtime image
-
observable
- healthcheck
- log to stdout
- prometheus endpoint
You can run either a forwarding server (that will send requests to an upstream), or a recursive one.
Then you can either expose a traditional DNS server, a TLS server, or both.
Examples:
... to a TLS upstream (encrypted). Cloudflare in this example:
docker run -d \
--env "DNS_FORWARD_UPSTREAM_NAME=cloudflare-dns.com" \
--env "DNS_FORWARD_UPSTREAM_IP_1=tls://1.1.1.1" \
--env "DNS_FORWARD_UPSTREAM_IP_2=tls://1.0.0.1" \
--net bridge \
--publish 53:53/udp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
docker.io/dubodubonduponey/dns
... same as above
docker run -d \
--env "DNS_FORWARD_UPSTREAM_NAME=cloudflare-dns.com" \
--env "DNS_FORWARD_UPSTREAM_IP_1=tls://1.1.1.1" \
--env "DNS_FORWARD_UPSTREAM_IP_2=tls://1.0.0.1" \
--env "DNS_OVER_TLS_ENABLED=true" \
--env "DNS_OVER_TLS_DOMAIN=dev-null.farcloser.world" \
--env "[email protected]" \
--net bridge \
--publish 443:443/tcp \
--publish 853:853/tcp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
docker.io/dubodubonduponey/dns
docker run -d \
--env "DNS_FORWARD_ENABLED=false" \
--net bridge \
--publish 53:53/udp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
docker.io/dubodubonduponey/dns
docker run -d \
--env "DNS_FORWARD_ENABLED=false" \
--env "DNS_OVER_TLS_ENABLED=true" \
--env "DNS_OVER_TLS_DOMAIN=dev-null.farcloser.world" \
--env "[email protected]"
--net bridge \
--publish 443:443/tcp \
--publish 853:853/tcp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
docker.io/dubodubonduponey/dns
For TLS, you do need to expose port 443 publicly from your docker host so that LetsEncrypt can issue your certificate, and of course, you need a DNS record that points to this ip.
If you want to customize your CoreDNS config, mount a volume into /config
on the container
(and customize one of the files to your needs).
chown -R 2000:nogroup "[host_path_for_config]"
docker run -d \
--volume [host_path_for_config]:/config:ro \
...
You can control the various ports used by the service if you wish to:
docker run -d \
--env DNS_PORT=53 \
--env DNS_OVER_TLS_PORT=853 \
--env DNS_OVER_TLS_LEGO_PORT=443 \
...
The default setup use CoreDNS config files in /config
that sets-up different scenarios based on the value of environment variables.
The /certs
folder is used to store LetsEncrypt certificates (it's a volume by default, which you may want to mount), in case you configure a DNS-over-TLS server.
You may specify the following environment variables at runtime:
For DoT:
- DNS_OVER_TLS_ENABLED: enable the DoT service
- DNS_OVER_TLS_DOMAIN (eg:
something.mydomain.com
) controls the domain name of your server - DNS_OVER_TLS_LEGO_PORT: port that lego will use to listen on for LetsEncrypt response
- DNS_OVER_TLS_LEGO_EMAIL (eg:
[email protected]
) controls the email used to issue your server certificate - DNS_OVER_TLS_LE_USE_STAGING controls whether you want to use LetsEncrypt staging environment (useful when debugging so not to burn your quota)
For forwarding:
- DNS_FORWARD_ENABLED: enable (default) or disable forwarding mode
- DNS_FORWARD_UPSTREAM_NAME: if you forward to a DoT server, the domain name of that service
- DNS_FORWARD_UPSTREAM_IP_1: the ip of the upstream
- DNS_FORWARD_UPSTREAM_IP_2: the backup ip of the upstream
You can also tweak the following:
- DNS_PORT (default to 53)
- DNS_OVER_GRPC_PORT (default to 553)
- DNS_STUFF_MDNS: convenient little trick to respond for certain mDNS queries over traditional DNS
- METRICS_PORT for Prometheuse (default to 9253)
Of course using any privileged port for these requires CAP_NET_BIND_SERVICE.
Finally, any additional arguments provided when running the image will get fed to the coredns
binary.
The default configuration files expose a Prometheus metrics endpoint on port 9253.
See DEVELOP.md