Setting up Pi-hole as a recursive DNS server using an Unbound container

In the last blogpost, we set up a Raspberry Pi to be a DNS level ad-blocker, using Ubuntu Server, Cockpit, Podman, and Pi-Hole.

Now lets go one step further and take back control by running our own recursive DNS server in a Podman container. We'll do this by installing an unbound container.

This is a follow-on from: Install Cockpit and Pi-Hole on your Raspberry Pi.

What you'll need

  • A computer running Ubuntu Server
  • Cockpit installed with the cockpit-podman addon
  • Optionally a Pi-Hole installation.

Create the Unbound config

SSH into your server, or use the 'Terminal' link in Cockpit.

Create a folder for your config file:

$ cd 
$ mkdir unbound/

Use nano (or your editor of choice) to create the config file for unbound:

/home/ubuntu/unbound/unbound.conf:

server:
    interface: 0.0.0.0
    verbosity: 0
    port: 53
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    do-ip6: no
    prefer-ip6: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no
    edns-buffer-size: 1232
    prefetch: yes
    num-threads: 1
    access-control: 10.0.0.0/8 allow
    access-control: 192.168.0.0/16 allow
    so-rcvbuf: 1m
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10

Create the Unbound container

Go to Cockpit, and click the 'Podman containers' link on the left-hand side.

Click on "Create container".

In the "Image" box, type "unbound", and choose the Docker image from Alpine. Set the following options:

  • Command - change to bash
  • Memory limit - change to 128 MB. It's a lightweight Alpine Linux container, that's more than enough
  • Restart policy - change to 'On failure', and '5 retries'

Podman Setup

Next, click on the 'Integration' Tab. Map the following ports if you're setting this up with a Pi-Hole container:

  • Port 5353/tcp -> 53/tcp
  • Port 5353/udp-> 53/udp

If you're just setting a recursive DNS server on it's own, and you don't have any other containers using port 53, then you can map directly:

  • Port 53/tcp -> 53/tcp
  • Port 53/udp-> 53/udp

Podman Setup

Next we need to create a link to the config file we created. Click on "Add volume", in "Host path" type the location of the config file, in my case, that was /home/ubuntu/unbound/unbound.conf. For the "Container path", set it to /etc/unbound/unbound.conf. Uncheck the "Writable" tickbox".

Podman Setup

Now click the "Create and run" link, in the blue box.

Test and update Pi-Hole

Once the container is up and running (it should be very quick, Alpine container images are very minimal), let's test it. Use the -p to pass through the correct port to the dig command.

$ dig @192.168.88.252 -p5353

; <<>> DiG 9.18.12-0ubuntu0.22.04.2-Ubuntu <<>> @192.168.88.252 -p5353
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8533
;; flags: qr rd ra; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;.              IN  NS

;; ANSWER SECTION:
.           86400   IN  NS  h.root-servers.net.
.           86400   IN  NS  i.root-servers.net.
.           86400   IN  NS  j.root-servers.net.
.           86400   IN  NS  k.root-servers.net.
.           86400   IN  NS  l.root-servers.net.
.           86400   IN  NS  m.root-servers.net.
.           86400   IN  NS  a.root-servers.net.
.           86400   IN  NS  b.root-servers.net.
.           86400   IN  NS  c.root-servers.net.
.           86400   IN  NS  d.root-servers.net.
.           86400   IN  NS  e.root-servers.net.
.           86400   IN  NS  f.root-servers.net.
.           86400   IN  NS  g.root-servers.net.

;; ADDITIONAL SECTION:
a.root-servers.net. 86400   IN  A   198.41.0.4
b.root-servers.net. 86400   IN  A   199.9.14.201
c.root-servers.net. 86400   IN  A   192.33.4.12
d.root-servers.net. 86400   IN  A   199.7.91.13
e.root-servers.net. 86400   IN  A   192.203.230.10
f.root-servers.net. 86400   IN  A   192.5.5.241
g.root-servers.net. 86400   IN  A   192.112.36.4
h.root-servers.net. 86400   IN  A   198.97.190.53
i.root-servers.net. 86400   IN  A   192.36.148.17
j.root-servers.net. 86400   IN  A   192.58.128.30
k.root-servers.net. 86400   IN  A   193.0.14.129
l.root-servers.net. 86400   IN  A   199.7.83.42
m.root-servers.net. 86400   IN  A   202.12.27.33
a.root-servers.net. 86400   IN  AAAA    2001:503:ba3e::2:30
b.root-servers.net. 86400   IN  AAAA    2001:500:200::b
c.root-servers.net. 86400   IN  AAAA    2001:500:2::c
d.root-servers.net. 86400   IN  AAAA    2001:500:2d::d
e.root-servers.net. 86400   IN  AAAA    2001:500:a8::e
f.root-servers.net. 86400   IN  AAAA    2001:500:2f::f
g.root-servers.net. 86400   IN  AAAA    2001:500:12::d0d
h.root-servers.net. 86400   IN  AAAA    2001:500:1::53
i.root-servers.net. 86400   IN  AAAA    2001:7fe::53
j.root-servers.net. 86400   IN  AAAA    2001:503:c27::2:30
k.root-servers.net. 86400   IN  AAAA    2001:7fd::1
l.root-servers.net. 86400   IN  AAAA    2001:500:9f::42
m.root-servers.net. 86400   IN  AAAA    2001:dc3::35

;; Query time: 48 msec
;; SERVER: 192.168.88.252#5353(192.168.88.252) (UDP)
;; WHEN: Tue Aug 22 22:09:29 BST 2023
;; MSG SIZE  rcvd: 811

Looks good! Last thing to do, is to login to Pi-Hole, go to Settings > DNS, and change the DNS server to our new container. The IP address will be the same as the Pi, use the # symbol to designate a non-standard port.

Podman Setup

Job done

I really hope this helps! If you'd like watch me do this on video, I've embedded a YouTube video below for your viewing pleasure.

Tools used

  • Ubuntu Server ARM 22.04.03 LTS
  • Cockpit >= 264
  • Podman>= 3.4.4
  • Alpine Linux Unbound container Latest pull from docker.io

More information

Ubuntu Server for Pi Cockpit Podman Pi-Hole Unbound

Setting up Pi-hole as a recursive DNS server solution

social