# Ручне встановлення Pi-hole DNS на прикладі Fedora / Linux

На сайті DOU є досить інформативний гайд з описом проєкту Pi-hole та причин користуватись ним сьогодні, на відміну від популярних uBlock і AdGuard:

=> https://dou.ua/forums/topic/54745/ Блокуємо рекламу за допомогою Pi Hole. Детальний гайд
* особисто я (через аналізатор Etherape) помічав за uBlock запити на статичне сховище Google, ймовірно за актуалізацією блок-списків, що мене також не влаштовує як мінімум.

Якщо коротко, то Pi-hole - дозволяє підняти локальний (або локально-мережний) проксі-сервер DNS з Веб-адмінкою, через яку можна наочно керувати правилами блокування та переглядати статистику запитів. При цьому, необхідність у високо-рівневих блокувальниках реклами відпадає, адже паразитний трафік не покидатиме "53 порт" локальної мережі ще на етапі резольву.

Взагалі, в мене були думки скористатись більш легкими рішеннями DNS, але Pi-hole заманив своєю візуалізацією і орієнтацією конкретно на потрібні мені задачі. У цьому матеріалі я не буду розглядати конкретний тюнінг блокування, але надам приклад ручного встановлення П/З, адже у всіх гайдах, які мені зустрілись нашвидкоруч - використовуються приклади інсталяції з Docker або автоматизованим скриптом:

``` bash
curl -sSL https://install.pi-hole.net | bash
```

Мене це не влаштовує, оскільки сам скрипт доволі великий (через свою універсальність) а також просить root, що тим паче потребує додаткового аналізу виконаних дій на моїй системі. Адже наприклад на Fedora я не користуюсь більше firewalld, а в офіційній документації - зустрічаються ось такі дозвільні приклади, коли як для мене відкриття 80 порту на всі інтерфейси не є прийнятним:

=> https://docs.pi-hole.net/main/prerequisites/#ufw

Отже, пробігшись по репозиторіям проєкту на GitHub, назбирав для себе такий мінімальний набір:

* FTL (Faster Than Light, pi-hole/FTL) - Це ядро комплексу Pi-hole, написане мовою C. Являє собою кастомізований DNS-сервер на базі dnsmasq і відповідає за блокування запитів та збір статистики
* Web UI (pi-hole/web) - Веб-панель для керування, що взаємодіє з бекендом FTL по API

## FTL

Спочатку, знадобляться як мінімум такі залежності:

``` bash
sudo dnf install gmp-static xxd mbedtls-devel
```

Забираємо початковий код і переходимо в його корінь:

``` bash
git clone https://github.com/pi-hole/FTL.git
cd FTL
```

## Компіляція

На цьому етапі, можна заглянути в `./build.sh`, але суть там наступна:

``` bash
mkdir build
cd build
cmake -DCMAKE_C_FLAGS="-fPIC" ..
cmake --build .
```
* для Fedora 43, я додав відсутній в скрипті аргумент `-DCMAKE_C_FLAGS="-fPIC"`

### Оновлення залежностей mbedtls-devel

Якщо на етапі збірки буде помилка:

``` bash
FTL/src/webserver/x509.c:232:19: error: too few arguments to function ‘mbedtls_x509write_crt_pem’; expected 5, have 3
  232 |         if((ret = mbedtls_x509write_crt_pem(&ca_cert, ca_buffer, sizeof(ca_buffer))) != 0)
```

Це значить, що у вас (як і в мене) в репозиторіях застаріла версія `mbedtls-devel`:

``` bash
$ dnf info mbedtls-devel | grep Version
Version         : 3.6.5
Version        : 3.6.5
```

=> https://github.com/pi-hole/FTL/issues/2778
=> https://docs.pi-hole.net/ftldns/compile/

``` bash
wget https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-4.0.0/mbedtls-4.0.0.tar.bz2 -O mbedtls-4.0.0.tar.bz2
tar -xjf mbedtls-4.0.0.tar.bz2
cd mbedtls-4.0.0
sed -i '/#define MBEDTLS_THREADING_C/s*^//**g' include/mbedtls/mbedtls_config.h
sed -i '/#define MBEDTLS_THREADING_PTHREAD/s*^//**g' include/mbedtls/mbedtls_config.h
cmake -S . -B build -DCMAKE_C_FLAGS="-fPIC -fomit-frame-pointer"
cmake --build build -j $(nproc)
sudo cmake --install build
```
* зверніть увагу: тут я додав до `-DCMAKE_C_FLAGS` аргумент `-fPIC`

Взагалі, коли змінюєте системні залежності в процесі відлову помилок компілятора, або довстановлюєте відсутні пакети `*-devel`, варто скидати поточний сетап з подальшою пере-конфігурацією проєкту:

``` bash
rm -rf *
cmake ..
cmake --build .
```

## Встановлення

Продовжуємо збірку Pi-hole і перевіряємо результат:

``` bash
./pihole-FTL verify
```

В корені FTL ще є корисні скрипти тестів, варто заглянути, але я їх не проходив:

```
FTL/test/run.sh
```

Далі я буду пускати сервер від systemd, тому мене влаштовує глобальна інсталяція від root:

``` bash
sudo cmake --install .
```

Вручну потрібно додати стандартні розташування:

``` bash
sudo mkdir -p /etc/pihole/config_backups
sudo mkdir -p /run/pihole
sudo mkdir -p /var/log/pihole

sudo touch /etc/pihole/dhcp.leases
sudo touch /var/log/pihole/FTL.log
sudo touch /var/log/pihole/pihole.log
sudo touch /var/log/pihole/webserver.log
```

А також видати на них права користувачеві, від якого планується запуск служби:

``` bash
sudo chown -R pihole:pihole /etc/pihole /run/pihole /var/log/pihole
```
* `pihole:pihole` (USER:GROUP) - ваше значення

## Налаштування

Якщо запустити сервіс на стандартному конфігі, то можна побачити як мінімум наступне:

``` bash
$ sudo ss -tulpn | grep pihole-FTL
udp   UNCONN 0      0                               0.0.0.0:53         0.0.0.0:*    users:(("pihole-FTL",pid=24659,fd=4))
udp   UNCONN 0      0                               0.0.0.0:53         0.0.0.0:*    users:(("pihole-FTL",pid=24294,fd=20))
tcp   LISTEN 0      200                             0.0.0.0:443        0.0.0.0:*    users:(("pihole-FTL",pid=24659,fd=29))
tcp   LISTEN 0      200                             0.0.0.0:80         0.0.0.0:*    users:(("pihole-FTL",pid=24659,fd=28))
tcp   LISTEN 0      200                                [::]:443           [::]:*    users:(("pihole-FTL",pid=24659,fd=31))
tcp   LISTEN 0      200                                [::]:80            [::]:*    users:(("pihole-FTL",pid=24659,fd=30))
```

Це означає, що якщо у вас є локальна мережа типу Yggdrasil, всі її користувачі зможуть безперешкодно звертатись на цей сервер за виключенням, якщо у вас налаштоване блокування через фаєрвол або в самій програмі це передбачено версією. Також я планую запуск цього серверу локально, тому `0.0.0.0/::` мені потрібно змінити на `127.0.0.1/::1`, звільнити 53, 80 порти (на формальні 5354 і 8053) і прибрати зайвий сокет 443 (HTTPs) - це робиться у файлі `/etc/pihole/pihole.toml`, який буде створено автоматично при першому запуску:

``` /etc/pihole/pihole.toml
[webserver]
port = "127.0.0.1:8053,[::1]:8053" ### CHANGED, default = "80o,443os,[::]:80o,[::]:443os"

[webserver.paths]
    # цей шлях можна змінити на свій
    #  або встановити до теки `/var/www/html/admin` корінь репозиторію:
    # `git clone https://github.com/pi-hole/web.git admin`
    webroot = "/var/www/html"

[dns]
listeningMode = "BIND" ### CHANGED, default = "LOCAL"
port = 5354 ### CHANGED, default = 53

[dns.reply.host]
IPv4 = "127.0.0.1" ### CHANGED, default = ""
IPv6 = "::1" ### CHANGED, default = ""
```

## Системний сервіс

``` bash
sudo useradd -s /usr/sbin/nologin -Mr pihole
```

``` /etc/systemd/system/pihole.service
[Unit]
Description=Pi-hole FTL DNS and Web Server
After=network.target

[Service]
User=pihole
Group=pihole

# дізнатись поточне розташування: `$ which pihole-FTL`
# всі опції запуску: `$ pihole-FTL --help`
ExecStart=/usr/bin/pihole-FTL -f

# AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
# CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN

# Restart=on-failure
# RestartSec=5s

[Install]
WantedBy=multi-user.target
```
* у цьому випадку використовується аргумент `-f` (*foreground*) бо в мене чомусь в бекграунді крашиться процес навіть з `forking`

## Налаштування системного резольвера

В Fedora я змінюю налаштування одним рядком у файлі:

``` /etc/systemd/resolved.conf
[Resolve]
DNS=127.0.0.1:5354
Domains=~.
# блокувати запити, якщо pi-hole DNS не доступний (лишити порожнім)
# FallbackDNS=
```

Тепер потрібно перезавантажити службу:

``` bash
sudo systemctl restart systemd-resolved
```

Переглянути статус:

``` bash
resolvectl status
```

Якщо все зроблено правильно, то у Веб-адмінці (за адресою у прикладі - http://localhost:8053/admin/) почне відображатись аналітика локальних запитів:

=> pi-hole-manual-install-on-fedora-linux/web-ui.png Вигляд адмінки Pi-hole (скріншот)

## pi-hole/pi-hole

Не був би-то піхол: згодом виявилось, що найважливіша функція білих/чорних списків все ще не працює при спробі оновити базу в адмінці. Для вирішення цієї проблеми, потрібен ще один компонент:

``` bash
git clone https://github.com/pi-hole/pi-hole
sudo mkdir -p /etc/.pihole
sudo cp -r pi-hole/advanced /etc/.pihole/
sudo chown pihole:pihole -R /etc/.pihole
```

А також:

``` bash
sudo mkdir -p /opt/pihole
sudo cp -r pi-hole/advanced/Scripts/* /opt/pihole
sudo install pi-hole/gravity.sh /opt/pihole
sudo chown pihole:pihole -R /opt/pihole
```
* можливо щось з того лінкується, але в мене це копії

І наостанок:

``` bash
sudo install pi-hole/pihole /usr/local/bin
```

Технічно, після цих маніпуляцій, повинна без помилок працювати відповідна функціональність в адмінці, а також команда ініціалізації бази списків "Gravity":

``` bash
sudo pihole -g
```

* Бонус: нарешті в `pi-hole/advanced/Templates/pihole-FTL.service`, я випадково знайшов приклад конфігурації сервісу systemd, де й дійсно для запуску потрібен аргумент `-f`.

## Висновки

Чесно кажучи, з цими кущами-хащами bash, я розчарувався в даному рішенні. Навіть, якщо в Pi-hole вгепано багато зусиль сісадмінів, що звикли спілкуватись з компом переважно мовою препроцесору і текстових конфігів. Для мене це не стабільність, не передбачувана поведінка через відсутність типізації і логічних помилок; залежність від контейнера.

Оскільки мені головою (замість процесора) переварювати цей баш в сирому вигляді і на живій системі не цікаво, шукатиму якесь інше рішення (див. crab-hole) а досвід - хай лишається на замітку.

## Дивіться також

=> crab-hole-as-pi-hole-alternative-in-rust.gmi Crab-hole DNS як 100% програмна альтернатива Pi-hole