Setting Up a Local DNS Service with Docker on Ubuntu 22.04
Tags: ubuntu, dns, docker, beginners
Published: 2024-03-24 22:20:18

Recently, I've been working on setting up a local DNS service using Docker on Ubuntu 22.04. I've documented my process and thought it might be helpful to share it with others. Here's how I did it.

Note: This article is the final form of these articles
- [Setting up a CoreDNS Server for Local Custom Domain Management on Ubuntu Using Docker - DEV Community](https://dev.to/mich0w0h/setting-up-a-coredns-server-for-local-custom-domain-management-on-ubuntu-using-docker-meo)
- [Setting Up a Recursive DNS Resolver Using Unbound on Docker - DEV Community](https://dev.to/mich0w0h/setting-up-a-recursive-dns-resolver-using-unbound-on-docker-1abg)

## Repository
You can find the complete code in my [GitHub repository](https://github.com/mich0w0h/local-dns).

## Project Structure

I've organized my project into a directory structure as follows:

```sh
local-dns
├── compose.yml
├── .git
├── .dockerignore
├── recursive
│   ├── Dockerfile
│   └── unbound.conf
└── authoritative
    ├── Corefile
    └── zone
        └── db.mich0w0h.house
```

## Networking Overview

Here's the networking overview of this project

![networking overview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a3i9xlj760zhfvb3oyx5.png)

I assigned an IP address 192.168.10.100 to the host Ubuntu server. If you want to know how to assign a static address to a Ubuntu server, see this post: [Configure Static IP in Ubuntu 22.04 - DEV Community](https://dev.to/mich0w0h/configure-static-ip-in-ubuntu-2204-2fd7)


## Docker Configuration

I've created a `.dockerignore` file to exclude unnecessary files from the Docker build context:

```dockerignore
**/.git
```

I've also created a Dockerfile for the resolver service:

```Dockerfile
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y unbound && rm -rf /var/lib/apt/lists/*

COPY unbound.conf /etc/unbound/unbound.conf

CMD ["/usr/sbin/unbound", "-d", "-c", "/etc/unbound/unbound.conf"]
```

This Dockerfile uses the Ubuntu 22.04 image, installs Unbound (a DNS resolver), and copies the Unbound configuration file into the container.

The Unbound configuration file (`unbound.conf`) is as follows:

```unbound.conf
server:
    interface: 0.0.0.0
    access-control: 0.0.0.0/0 refuse
    access-control: 192.168.1.0/24 allow_snoop
remote-control:
    control-enable: no
stub-zone:
    name: "mich0w0h.house"
    stub-addr: 192.168.1.102
forward-zone:
    name: "."
    forward-addr: 8.8.8.8 # google DNS
    # forward-addr: 192.168.10.1. # ISP provided DNS
```

## Docker Compose

I've used Docker Compose to manage my services. Here's my `compose.yml` file:

```yml
services:
  resolver:
    build: ./resolver
    ports:
      - "53:53/udp"
    networks:
      local-dns:
        ipv4_address: 192.168.1.101
  authoritative:
    image: coredns/coredns
    volumes:
      - "./authoritative:/etc/coredns"
    networks:
      local-dns:
        ipv4_address: 192.168.1.102
    command: -conf /etc/coredns/Corefile
networks:
  local-dns:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.1.0/24
```

The service is available from port 53 of the host machine. However, it's necessary to assign IP addresses since `unbound.conf` only accepts IP addresses to specify the nameserver, and specifying the service name of docker compose doesn't work.


If you've already created a network using the command `sudo docker network create --subnet=192.168.1.0/24 local-dns`, you can modify the networks section like this:

```yml
networks:
  local-dns:
    external: true
```

## Enabling Port Mapping

By default, `systemd-resolved` is running on port 53 in Ubuntu 22.04. To use port 53 for your Docker container, you'll need to stop and disable `systemd-resolved`, or change its port. Here's how I did it:

```bash
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
```

Next, remove the symlink `/etc/resolv.conf` and create a new one:

```bash
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
```

After this, test your internet connectivity to ensure that disabling `systemd-resolved` hasn't caused any issues:

```sh
$ curl google.com
```

## Running Docker Compose

To start your services, run Docker Compose:

```sh
sudo docker compose up -d --build
```

## Testing

Finally, test your setup from another device in your home network:

```sh
$ dig @192.168.10.100 www.mich0w0h.house
```

If everything is set up correctly, you should see a response similar to the following:

```sh
; <<>> DiG 9.10.6 <<>> @192.168.10.100 www.mich0w0h.house
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49784
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.mich0w0h.house.		IN	A

;; ANSWER SECTION:
www.mich0w0h.house.	86400	IN	A	192.168.1.103

;; Query time: 49 msec
;; SERVER: 192.168.10.100#53(192.168.10.100)
;; WHEN: Sun Mar 24 05:19:39 JST 2024
;; MSG SIZE  rcvd: 63
```

That's it! You've now set up a local DNS service with Docker on Ubuntu 22.04.

## References
- [DNSがよくわかる教科書 | SBクリエイティブ](https://www.sbcr.jp/product/4797394481/)
- [開発系エンジニアのためのDocker絵とき入門 - 秀和システム あなたの学びをサポート！](https://www.shuwasystem.co.jp/book/9784798071503.html)
- [Configuration — Unbound 1.19.3 documentation](https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/configuration.html)
- [NLnet Labs Documentation - Unbound - unbound-checkconf.8](https://nlnetlabs.nl/documentation/unbound/unbound-checkconf/)
- [NLnet Labs Documentation - Unbound - unbound.conf.5](https://nlnetlabs.nl/documentation/unbound/unbound.conf/)
- [Resolver for Home Networks — Unbound 1.19.3 documentation](https://unbound.docs.nlnetlabs.nl/en/latest/use-cases/home-resolver.html)
- [Corefile Explained](https://coredns.io/2017/07/23/corefile-explained/)
- [Docker+DNS入門　その1：CoreDNSを用いた権威DNSサーバ構築 #Docker - Qiita](https://qiita.com/miwamoto/items/2a8befac7135bd21e08a)
- [Docker+DNS入門　その2：Unboundを用いたキャッシュDNSサーバ構築 #Docker - Qiita](https://qiita.com/miwamoto/items/7981c390ac876a7fac5e)