DEV Community

Cover image for Deploying Pi-hole DNS Sinkhole Service on Ubuntu 24.04
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya • Originally published at docs.vultr.com

Deploying Pi-hole DNS Sinkhole Service on Ubuntu 24.04

Pi-hole is a network-level ad and tracker blocking application that acts as a DNS sinkhole, returning a null address for known ad and tracking domains. This guide deploys Pi-hole using Docker Compose with Traefik handling automatic HTTPS for the admin dashboard, after freeing the system's port 53. By the end, you'll have Pi-hole resolving and sinkholing DNS queries with an HTTPS-secured admin console.


Free Port 53

Ubuntu's systemd-resolved binds port 53 by default. Release it before deploying.

1. Stop and disable systemd-resolved:

$ sudo systemctl stop systemd-resolved
$ sudo systemctl disable systemd-resolved
Enter fullscreen mode Exit fullscreen mode

2. Replace the resolver configuration:

$ sudo rm /etc/resolv.conf
$ echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf
Enter fullscreen mode Exit fullscreen mode

Set Up the Directory Structure

1. Create the project directory structure:

$ mkdir -p ~/pihole/{etc-pihole,etc-dnsmasq.d,letsencrypt}
$ cd ~/pihole
Enter fullscreen mode Exit fullscreen mode

2. Create the environment file:

$ nano .env
Enter fullscreen mode Exit fullscreen mode
DOMAIN=pihole.example.com
LETSENCRYPT_EMAIL=admin@example.com
TZ=UTC
Enter fullscreen mode Exit fullscreen mode

Deploy with Docker Compose

1. Add your user to the Docker group:

$ sudo usermod -aG docker $USER
$ newgrp docker
Enter fullscreen mode Exit fullscreen mode

2. Create the Docker Compose manifest:

$ nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode
services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    environment:
      DOCKER_API_VERSION: "1.44"
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=traefik-public"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--certificatesresolvers.le.acme.httpchallenge=true"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt

  pihole:
    image: pihole/pihole:latest
    container_name: pihole
    restart: unless-stopped
    environment:
      TZ: ${TZ}
    volumes:
      - ./etc-pihole:/etc/pihole
      - ./etc-dnsmasq.d:/etc/dnsmasq.d
    ports:
      - "53:53/tcp"
      - "53:53/udp"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pihole.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.pihole.entrypoints=websecure"
      - "traefik.http.routers.pihole.tls=true"
      - "traefik.http.routers.pihole.tls.certresolver=le"
      - "traefik.http.services.pihole.loadbalancer.server.port=80"
Enter fullscreen mode Exit fullscreen mode

3. Start the services:

$ docker compose up -d
Enter fullscreen mode Exit fullscreen mode

4. Verify the services are running:

$ docker compose ps
Enter fullscreen mode Exit fullscreen mode

Initial Configuration

1. Set the admin password:

$ docker compose exec pihole pihole setpassword
Enter fullscreen mode Exit fullscreen mode

2. Open the dashboard:

Open https://pihole.example.com/admin in a browser and sign in.

3. Permit dashboard access from all origins:

Go to Settings → DNS, toggle Basic to access advanced settings, and select Permit all origins under Interface Settings. Save & Apply.

Warning: Restrict access to port 53 with your firewall — open DNS resolvers can be abused for amplification attacks.


Test Resolution

From any client, confirm blocking and normal resolution:

$ dig @SERVER_IP flurry.com
$ dig @SERVER_IP vultr.com
Enter fullscreen mode Exit fullscreen mode

The first should resolve to 0.0.0.0; the second should return real records.


Next Steps

Pi-hole is running with HTTPS for the dashboard. From here you can:

  • Add custom blocklists via Adlists in the dashboard
  • Enable conditional forwarding to your LAN router for local hostname resolution
  • Point your LAN DHCP server at Pi-hole for network-wide filtering

For the full guide with additional tips, visit the original article on Vultr Docs.

Top comments (0)