Pi-hole Docker – це спосіб винести DNS-блокування реклами на рівень усієї мережі, не ставлячи сервіс напряму в систему хоста. У homelab такий варіант дає ізоляцію, простіше оновлення і чистіший rollback. Нижче – робоча схема розгортання, вибір мережевого режиму, перевірка резолвінгу і місця, де Pi-hole у Docker зазвичай ламається.
Практичний результат тут простий: клієнти в LAN починають ходити на Pi-hole як на основний DNS, запити фільтруються на рівні доменів, а сам контейнер не конфліктує з локальним resolver на хості. Найбільше проблем не з фільтрацією, а з мережею Docker, портом 53 і неправильним DHCP або DNS на маршрутизаторі.
Pi-hole добре працює як DNS sinkhole для домашньої інфраструктури, тестових VLAN і невеликих self-hosted мереж. Але якщо в мережі вже є складний локальний DNS, split-horizon з кількома зонами або жорстка прив’язка до існуючого resolver, контейнеризація потребує акуратнішої схеми, інакше починаються дивні таймаути та петлі резолвінгу.
Який мережевий режим вибрати для Pi-hole у Docker
Для Pi-hole у Docker вибір мережевого режиму важливіший за сам контейнер. Якщо потрібен просто DNS-сервер для LAN, найменше сюрпризів дає host або окрема IP-адреса через macvlan. Режим bridge теж працює, але частіше створює проблеми з портами, видимістю клієнтів і додатковими правилами NAT.
host зручний там, де хост не використовує власний DNS на порту 53. Контейнер слухає мережу хоста без пробросу портів, а клієнти бачать сервіс напряму. Мінус очевидний: якщо на машині вже працює systemd-resolved, dnsmasq або інший локальний resolver, конфлікт майже гарантований.
bridge має сенс, коли потрібна стандартна модель Docker і контроль портів. Але DNS через NAT – не найелегантніша історія. Частина запитів працює штатно, частина діагностики стає незручною, а в складніших схемах з conditional forwarding це лише додає шуму.
macvlan дає контейнеру окрему адресу в LAN. Для Pi-hole це майже ідеальний компроміс: немає конфлікту з DNS хоста, сервіс виглядає як окремий вузол, клієнтський трафік видно чистіше. Нюанс у тому, що хост зазвичай не може напряму ходити до контейнера через той самий macvlan без додаткової мережевої схеми. У homelab це часто спливає вже після розгортання, коли веб-інтерфейс із самого сервера раптом недоступний.
Як розгорнути Pi-hole у Docker через docker compose
Найпростіша схема для старту – окремий каталог, постійні томи для конфігурації і проброс DNS та веб-інтерфейсу. Якщо на хості вже зайнятий порт 53, спочатку прибирають локальний resolver з цього порту, а вже потім піднімають контейнер.
mkdir -p ~/pihole
cd ~/pihole
cat > compose.yml <<'EOF'
services:
pihole:
image: pihole/pihole:latest
container_name: pihole
restart: unless-stopped
ports:
- "53:53/tcp"
- "53:53/udp"
- "8080:80/tcp"
environment:
TZ: "Europe/Kyiv"
FTLCONF_webserver_api_password: "changeme"
volumes:
- ./etc-pihole:/etc/pihole
- ./etc-dnsmasq.d:/etc/dnsmasq.d
cap_add:
- NET_ADMIN
EOF
docker compose up -d
Такий варіант підходить для стартового стенда або для хоста без локального DNS на 53 порту. Веб-інтерфейс у цьому прикладі винесений на 8080, щоб не зачепити вже зайнятий 80 порт. Якщо хост чистий, порт можна залишити стандартним.
Після запуску перевіряють, чи контейнер справді слухає DNS:
docker ps ss -lntup | grep :53 curl -I http://127.0.0.1:8080/admin/
Далі на маршрутизаторі або DHCP-сервері як DNS для клієнтів виставляють IP вузла з Pi-hole. Сам контейнер ще не означає, що мережа почне ним користуватись. Без зміни DNS для клієнтів блокування реклами залишиться локальним експериментом.
Чому Pi-hole у Docker конфліктує з портом 53
Конфлікт із портом 53 – найтиповіша проблема при запуску Pi-hole у Docker. На Linux-хості цей порт часто вже зайнятий локальним resolver. Docker тут ні до чого: контейнер просто не може прив’язатися до сокета, який уже використовується іншою службою.
Найчастіше винен systemd-resolved. На Debian, Ubuntu та похідних він слухає локальний DNS stub resolver. Перевірка проста:
ss -lntup | grep :53 systemctl status systemd-resolved
Якщо порт зайнятий, є кілька шляхів. Перший – перевести хост на резолвінг без локального stub і звільнити 53 порт. Другий – не використовувати host/ports на цьому хості, а дати Pi-hole окрему адресу через macvlan. Третій – винести сервіс на іншу машину. Для постійного homelab найчистіший варіант часто саме окрема IP-адреса, а не боротьба з локальною DNS-службою хоста.
Тут є неочевидний момент. Навіть якщо контейнер стартував, хост може все одно продовжити резолвити через старий локальний resolver, а клієнти – через Pi-hole. У результаті частина перевірок покаже, що блокування працює, а частина – що ні. Це не помилка Pi-hole, а дві різні DNS-траєкторії в одній системі.
Що змінити на маршрутизаторі, щоб блокування працювало для всієї мережі
Щоб Pi-hole у Docker реально блокував рекламу на рівні мережі, клієнти мають отримати саме його як DNS-сервер. Найправильніше це робити через DHCP на маршрутизаторі або окремому DHCP-сервері. Ручна зміна DNS на кожному пристрої працює, але для LAN це тимчасовий обхід, а не нормальна схема.
У типовому сценарії достатньо вказати IP Pi-hole як primary DNS у DHCP-опціях. Якщо є secondary DNS, частина клієнтів піде повз фільтрацію. Це стара проблема, але її регулярно недооцінюють: другий DNS не є резервом у звичному сенсі, деякі клієнти використовують його паралельно. Якщо потрібне повне доменне блокування, сторонній secondary DNS краще не видавати.
Для локальних імен у homelab часто залишають upstream DNS на маршрутизатор, Unbound або локальний recursive resolver. Якщо в мережі є внутрішні домени, краще відразу продумати, хто авторитетний за локальні записи. Pi-hole як фронт до локального DNS працює нормально, але як єдине місце для всього резолвінгу він швидко починає обростати винятками.
Як перевірити, що Pi-hole у Docker працює коректно
Перевірка має бути двошаровою: окремо доступність DNS-сервісу, окремо факт фільтрації. Якщо перевіряти лише веб-інтерфейс, можна пропустити зламаний UDP 53. Якщо дивитись лише на блокування доменів, легко не помітити, що частина клієнтів взагалі обходить Pi-hole у Docker.
Спочатку перевіряють резолвінг напряму через IP сервера:
dig @192.168.1.10 example.org nslookup example.org 192.168.1.10
Потім дивляться, чи клієнт реально використовує потрібний DNS. На Linux це видно через resolvectl або /etc/resolv.conf, на маршрутизаторі – через lease, на самому Pi-hole – через query log у веб-інтерфейсі. Якщо клієнт не з’являється в логах, проблема не в списках блокування, а в шляху DNS-трафіку.
Окремо варто перевірити кілька типів доменів: звичайний домен, відомий рекламний домен і локальне ім’я з homelab. Саме останній тест часто ламає гарну картинку. Блокування працює, а локальні записи – ні, бо upstream DNS не знає про внутрішню зону.
Де Pi-hole у Docker найчастіше ламається в homelab
У homelab Pi-hole у Docker найчастіше ламається не через контейнер, а через суміжні сервіси. Типові збої – подвійний DNS, некоректний DHCP, неправильний upstream resolver і спроба поєднати bridge-мережу з очікуванням, що все виглядатиме як окремий фізичний вузол.
- Клієнти отримують два DNS-сервери, і частина запитів минає фільтрацію.
- Хост використовує один resolver, а мережа – інший, тому тести дають суперечливий результат.
- Локальні домени не резолвляться, бо Pi-hole не передає їх на потрібний upstream.
- Контейнер піднятий у bridge, але від нього очікують поведінку окремого LAN-хоста.
- Після оновлення Docker або хоста міняються мережеві правила, і UDP 53 починає поводитись нестабільно.
Є ще одна межа застосовності. Якщо в мережі кілька VLAN, окремі політики DNS, split DNS для VPN-клієнтів і власний authoritative DNS, Pi-hole у Docker перестає бути центральним рішенням і стає лише фільтруючим шаром. На цьому етапі краще розділити ролі: окремо резолвер, окремо рекурсія, окремо блокування. Інакше будь-яка дрібна зміна в LAN зачіпає одразу весь DNS-ланцюг.
Коли замість Pi-hole у Docker краще вибрати інший підхід
Pi-hole у Docker має сенс там, де потрібне швидке мережеве блокування реклами, базовий контроль DNS і просте обслуговування. Якщо ж основна задача – повний локальний DNS для складної інфраструктури, контейнер із Pi-hole краще не ставити в центр усієї схеми. Він добре фільтрує, але не замінює продуману DNS-архітектуру.
Для маленького homelab це майже оптимальний варіант. Для мережі з кількома підмережами, VPN і купою внутрішніх сервісів часто краще ставити Pi-hole перед окремим recursive resolver або інтегрувати його тільки як фільтр. Це грубіше на старті, зате далі менше дивних ефектів із локальними зонами й політиками маршрутизації DNS.
Офіційний сайт проєкту: Pi-hole. Контейнерний образ і приклади розгортання: pihole/pihole на Docker Hub.