Ubuntu 20.04 LTS, Docker & PiHole

This article details (most of) the instructions for installing and configuring PiHole on Docker on Ubuntu 20.04.

Step 1: Install Ubuntu 20.04.

There are plenty of tutorials on the Internet detailing how to do this, so I will not reinvent the wheel. Here are a few links for your reference:

Step 1.5: Update.

Update your new install with the latest security patches and updates:

sudo apt-get update

sudo apt-get upgrade

Step 1.75: setup IP & DNS

Configure you new system with an IP address and DNS name as per the idiosyncrasies of your environment.

The first and a half and first and three quarters steps are optional.

Step 2: Install Docker.

www.williammax.com/how-to-install-docker

Step 3: Install Docker Compose.

www.williammax.com/how-to-install-docker-compose

Step 4: Configure Docker to run as normal user.

sudo usermod -aG docker $USER

Note: if the docker group does not already exist you can create it with the following command:

sudo groupadd docker

Step 5: Stop systemd-resolve from listening on port 53

This was a new one for me and is what prompted this tutorial. One of the changes Ubuntu 20.04 LTS is systemd-resolve is configured to listen on port 53. Apparently, systemd-resolve has been around since Ubuntu 16.04 and until 20.04 this was not a problem (at least for me).

Having systemd-resolve perform DNS lookups makes sense for well...reasons. It will cache DNS lookups improving performance for applications which do not do this themselves, it improves privacy and somehow works better when doing split DNS lookups (like when you are on a VPN).

However, if you want to run your own DNS server you need to stop systemd-resolve from listening on Port 53, which if we want to run PiHole is necessary. If you don't PiHole will refuse to start up.

When I upgraded to 20.04 I spent a lot of time trying to figure why PiHole would not startup, what was listening on port 53 and finally how to stop it without breaking anything critical (like DNS lookups). Once I did figure this out it turned out to be quite easy.

  1. Edit /etc/systemd/resolved.conf
  2. Uncomment the line with DNSStubListener and change yes to no.

Your file should look something like this:

#  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=no-negative
DNSStubListener=no
#ReadEtcHosts=yes

Then restart systemd-resolved with the following command:

sudo systemctl restart systemd-resolved.service

Now that systemd-resolved is no longer listening on port 53, local DNS name resolution will no longer work :-(

To fix this run the following commands:

sudo rm /etc/resolv.conf

sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

Now you should be all good.

A bit of explanation...

The issue with systemd-resolved is a chicken and egg problem. Systemd-resolved is doing DNS lookups. It is running on port 53. If systemd-resolved is running on port 53 then PiHole cannot run on port 53, but if systemd-resolved is not available on port 53, then the local system can do DNS lookups which effectively means that it cannot connect to the Internet and cannot download PiHole.

So, the solution is to stop systemd-resolved from running on port 53 and then remove the symbolic link from /etc/resolv.conf to /run/systemd/resolve/stub-resolve.conf and replace it with a symbolic link to /run/systemd/resolve/resolv.conf.

Step 6: Create PiHole docker-compose.yml

version: "3"

# More info at https://github.com/pi-hole/docker-pi-hole/ and https://docs.pi-hole.net/
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "8000:80/tcp"
      - "8443:443/tcp"
    environment:
      TZ: 'America/New_York'
      WEBPASSWORD: <YOUR_PASSWORD>
      VIRTUAL_HOST: <YOUR_IP_ADDRESS>:8000
    # Volumes store your data between container upgrades
    volumes:
      - './etc-pihole/:/etc/pihole/'
      - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
    dns:
      - <YOUR DNS SERVER>
    # Recommended but not required (DHCP needs NET_ADMIN)
    #   https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
    cap_add:
      - NET_ADMIN
    restart: unless-stopped

Step 7: start PiHole

docker-compose up -d

Done!