Introduction
Pi-hole is a network-wide DNS filtering solution that blocks advertisements, trackers, and malicious domains before they reach your devices.
In this tutorial, you will install Docker, Docker Compose, and deploy Pi-hole inside a Docker container on a Debian or Ubuntu server. At the end of this guide, you will have a fully functional Pi-hole instance accessible through a web interface and ready to serve DNS requests for your network.
Prerequisites
- A server
- Debian 12/13 or Ubuntu 24.04/26.04
- Root or sudo access
- A static IP address
- Open ports
53/tcp,53/udp, and80/tcp - Docker already installed
Example terminology
Throughout this tutorial, the following placeholders are used:
- Hostname:
<your_host> - Server IP:
<10.0.0.1> - Password:
<your_password>
Step 1 - Install Docker
If you haven't already, install Docker now as explained in the official Docker documentation:
Remember to add your user to the docker group:
sudo usermod -aG docker your-user-nameStep 2 - Create the Pi-hole Directory Structure
Create a directory for Pi-hole:
mkdir -p ~/pihole
cd ~/piholeCreate persistent storage directories:
mkdir -p ~/pihole/etc-pihole
mkdir -p ~/pihole/etc-dnsmasq.d
touch ~/pihole/docker-compose.ymlYour structure should look like:
~/pihole
├── docker-compose.yml
├── etc-pihole
└── etc-dnsmasq.dStep 3 - Create the Docker Compose Configuration
Create the compose file:
nano docker-compose.ymlInsert the following configuration which uses the Docker image pihole/pihole:
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
environment:
TZ: Europe/Bratislava
FTLCONF_webserver_api_password: "ChangeMe123!"
ports:
- "53:53/tcp"
- "53:53/udp"
- "80:80/tcp"
volumes:
- ./etc-pihole:/etc/pihole
- ./etc-dnsmasq.d:/etc/dnsmasq.d
restart: unless-stoppedSave and close the file.
Step 4 - Start Pi-hole
Start the container:
docker compose up -dIf you get an error message like Error response from daemon: failed to set up container networking, go to Step 9 - Troubleshooting: Port 53 Already in Use.
Verify that the container is running:
docker psExpected output:
CONTAINER ID IMAGE STATUS PORTS NAMES
xxxxxxxxxxxx pihole/pihole:latest Up (healthy) 0.0.0.0:53->53/tcp, ... piholeClick here if the ports section is empty
The ports section should look like this:
0.0.0.0:53->53/tcp, [::]:53->53/tcp, 67/udp, 0.0.0.0:80->80/tcp, 0.0.0.0:53->53/udp, [::]:80->80/tcp, [::]:53->53/udp, 123/udp, 443/tcpIf this section is empty for you, stop and remove the container are restart it:
docker stop pihole && docker rm pihole docker compose up -d docker ps
View the logs:
docker compose logs -fPress CTRL+C to exit.
Step 5 - Access the Web Interface
Open your browser and navigate to:
http://<10.0.0.1>/adminReplace <10.0.0.1> with the IP address of your server.
Log in using the password configured in docker-compose.yml:
FTLCONF_webserver_api_password: "ChangeMe123!"After logging in, you should see the Pi-hole dashboard.
Step 6 - Configure DNS Clients
To use Pi-hole, configure your devices or router to use the Pi-hole server as their DNS server.
Example:
Primary DNS: <10.0.0.1>
Secondary DNS: (leave empty)For best results, configure DNS directly on your router so all devices automatically use Pi-hole. Learn more, in the official Pi-hole documentation:
- Making your network take advantage of Pi-hole
- Configure your router to have DHCP clients use Pi-hole as their DNS server
- Use Pi-hole's built-in DHCP server
Step 7 - Update Pi-hole
| Pull the latest image |
|
| Restart the container |
|
| Verify the running version |
|
Step 8 - Useful Commands
| View logs |
|
| Restart Pi-hole |
|
| Stop Pi-hole |
|
| Start Pi-hole |
|
| Check container status |
|
Step 9 - Troubleshooting: Port 53 Already in Use
When starting the Pi-hole container, you may encounter an error similar to:
failed to bind host port 0.0.0.0:53/tcp: address already in useThis means another service is already listening on DNS port 53.
Check which service is using the port:
sudo ss -tulpn | grep ':53'-
Ubuntu -
systemd-resolvedSome Ubuntu installations use
systemd-resolvedwhich occupies port53.Stop and disable the service:
sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolvedCreate a new DNS configuration:
cat <<EOF | sudo tee /etc/resolv.conf nameserver 1.1.1.1 nameserver 8.8.8.8 EOFVerify DNS resolution:
ping -c 4 google.com
-
Debian -
dnsmasqSome Debian installations may have
dnsmasqinstalled.Check its status:
sudo systemctl status dnsmasqIf it is running and you do not need it, stop and disable it:
sudo systemctl stop dnsmasq sudo systemctl disable dnsmasq
-
Verify Port Availability
Ensure that nothing is listening on port
53:sudo ss -tulpn | grep ':53'If no output is returned, start Pi-hole again:
cd ~/pihole docker compose up -dVerify the container status:
docker ps
Conclusion
You have successfully installed Docker and deployed Pi-hole using Docker Compose on Debian or Ubuntu. Your server is now capable of providing network-wide DNS filtering and blocking advertisements, trackers, and malicious domains for all devices that use it as their DNS server.