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.

Please note: all the following should be a single line. Any line wrapping should be "undone" before running commands.

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

curl -fsSL | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] $(lsb_release -cs) stable"

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli

Step 3: Install Docker Compose.

Again the following command is a single line, "undo" any line wrapping.

sudo curl -L "$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

And set permissions:

sudo chmod +x /usr/local/bin/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

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/resolve.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 and
    container_name: pihole
    image: pihole/pihole:latest
      - "53:53/tcp"
      - "53:53/udp"
      - "67:67/udp"
      - "8000:80/tcp"
      - "8443:443/tcp"
      TZ: 'America/New_York'
    # Volumes store your data between container upgrades
      - './etc-pihole/:/etc/pihole/'
      - './etc-dnsmasq.d/:/etc/dnsmasq.d/'
    # Recommended but not required (DHCP needs NET_ADMIN)
      - NET_ADMIN
    restart: unless-stopped

Step 7: start PiHole

docker-compose up -d


~ Read next post in System Administration ~

Tips & Tricks for working with Traefik

Posted by Max

2 min read