Як заблокувати рекламу в застосунках на Apple-девайсах: DNS-over-HTTPS сервер для Pi-hole
Привіт! Мене звати Олександр Ющенко, я військовослужбовець НГУ і Software Engineer. Ця стаття частково базується на туторіалі від Богдана Свердлюка по налаштуванню Pi-Hole. Це прекрасний матеріал, і я раджу прочитати його перед тим, як виконувати дії в цій статті.
Нижчеописане рішення дозволяє блокувати банеру рекламу та відеорекламу і в браузері, і в застосунках (при правильному налаштуванні блок-лістів в Pi-hole). Наприкінці бонус для тих, хто хоче спробувати, як це працює, проте не хоче робити купу налаштувань для цього.
Ця стаття також буде корисна тим, хто використовує сторонні блокувальники реклами на iOS, які можуть не давати той рівень функціональності, кастомізації чи приватності, який може дати власний сервер з Pi-hole. Особливо це корисно тим, хто хоче замінити мобільний Adguard і не знає альтернативи.
Проте проблема Pi-hole «з коробки» в тому, що він підтримує лише звичайний незашифрований DNS. Для більшості побутових задач цього достатньо, але суттєвий недолік цього рішення — він не блокує рекламу всередині застосунків на Apple-девайсах. Починаючи з iOS 14 Apple надала можливості використання DoH (DNS over HTTPS) для шифрування DNS-запитів, ускладнення DNS спуфінгу і, очевидно, щоб рекламу було не так легко заблокувати. Отже, реклама всередині застосунків резолвиться за допомогою DoH через DNS-сервери, визначені рекламним SDK, оминаючи DNS, вказаний для мережі. Ця поведінка не повʼязана з тим, чи увімкнено Private Relay.
Але це вирішується за допомогою додавання системної політики для пристрою, яка б змушувала використовувати потрібний DNS-сервер через HTTPS.
Початкові умови
Обладнання та софт, що я використовував:
- HP Elitedesk 800 G4 mini
- Proxmox VE 8
- Nginx Proxy Manager (LXC)
- Pi-hole (LXC)
- Unbound (recursive proxy)
- doh-server
- TP-Link Omada VPN Router
- Omada Cloud Controller
- Cloudflare
- Куплений домен
- Таблиця DNS
Моя конфігурація трохи відрізняється від статті Богдана, оскільки я використовую Unbound для того, щоб резолвити DNS незалежно від провайдерів, але в даному матеріалі ми розбиратимемо шлях до Pi-Hole.
План
Відповідно, план полягатиме в тому, щоб запустити деякий сервіс, який перетворював би DoH в звичайний DNS запит і відправляв би його на Pi-hole.
Для цього можна використовувати doh-server від DNSCrypt. Зараз це open-source рішення доволі нове і має версію 0.9. Альтернативно можна використовувати dnscrypt-proxy та налаштувати його таким чином, щоб перенаправляти запити на Pi-Hole, але, на мою думку, це ускладнює рішення.
В моїй конфігурації doh-server працюватиме через http-протокол, хоча програма має вбудовані можливості використовувати TLS, вказавши в аргументах шлях до сертифікату.
Цього б було достатньо для домашнього використання, але я також хочу, щоб це рішення працювало за межами локальної мережі. Для цього треба повʼязати IP DoH-сервера та домен в Cloudflare DNS-таблиці, покинути порт завдяки port forwarding на роутері та налаштувати проксі з https в nginx proxy manager.
Ось спрощена схема:

Встановлюємо doh-server
- Завантажуємо та встановлюємо відповідний пакет для вашої системи
- Для x86:
wget https://github.com/DNSCrypt/doh-server/releases/download/0.9.15/doh-proxy_0.9.15-1_amd64.deb sudo apt install ./doh-proxy_0.9.15-1_amd64.deb
- Для ARM:
wget https://github.com/DNSCrypt/doh-server/releases/download/0.9.15/doh-proxy_0.9.15-1_arm64.deb sudo apt install ./doh-proxy_0.9.15-1_arm64.deb
- Для x86:
- Додаємо запуск сервісу:
- Створюємо файл:
sudo nano /etc/systemd/system/doh-proxy.service
- Додаємо вміст:
[Unit] Description=DNS-over-HTTPS Proxy After=network.target [Service] ExecStart=/usr/bin/doh-proxy \ -H ’doh.yourdomain.com’ \ ## Домен за яким буде доступний сервер -u 127.0.0.1:53 \ ## IP-адреса і порт де запущено Pi-hole -l 0.0.0.0:3000 ## запускаємо сервіс на порту 3000 для доступу з усіх IP User=nobody Group=nogroup [Install] WantedBy=multi-user.target
Якщо використовуєте doh-server та nginx на одному хості — можна видалити-l 0.0.0.0:3000. Тоді сервіс буде запускатись і доступний через порт 3000 для використання на localhost (127.0.0.1). Але тоді ви не зможете перевірити роботу з іншого пристрою напряму (пункт 3). - Підвантажуємо файл сервісу та запускаємо.
sudo systemctl daemon-reload sudo systemctl enable —now doh-proxy
- Створюємо файл:
- Перевіряємо роботу з іншого пристрою в локальній мережі.
curl -v -H 'accept: application/dns-json' 'http://<ip-адреса>:3000/dns-query?name=example.com&type=A'
в результаті маємо отримати приблизно таку відповідь:{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"example.com","type":1}],"Answer":[{"name":"example.com","type":1,"TTL":0,"data":"23.192.228.80"},{"name":"example.com","type":1,"TTL":0,"data":"23.215.0.138"},{"name":"example.com","type":1,"TTL":0,"data":"23.192.228.84"},{"name":"example.com","type":1,"TTL":0,"data":"23.220.75.245"},{"name":"example.com","type":1,"TTL":0,"data":"23.215.0.136"},{"name":"example.com","type":1,"TTL":0,"data":"23.220.75.232"}]}
Дізнатись ip в локальній мережі можна, виконавши команду ip a.
Налаштування домену
Cloudflare (якщо є свій домен)
- Дізнаємось свою публічну IP-адресу.
curl ifconfig.me
- Логінимось в акаунт та переходимо до таблиці DNS-записів.

- Додаємо запис з вашою публічною IP-адресою та тимчасово вимикаємо Proxy status.
- Переходимо в профіль -> API Tokens та створюємо токен для DNS Challenge, щоб згенерувати SSL-сертифікат.
Надаємо права на Zone.Zone Read, Zone.DNS Edit.
Duck DNS (якщо немає свого домену)
- Логінимось або реєструємо акаунт.
- Додаємо домен (одразу заповниться ваш IP).

Примітка: багато провайдерів ховають клієнтів за NAT, тому навіть динамічна публічна адреса може не спрацювати. Краще уточнити цей нюанс і за необхідності підключити статичну IP-адресу.
Налаштовуємо Nginx Proxy Manager
- Додаємо Proxy Host.
Вказуємо наш домен, протокол http, IP-адресу doh-server та порт 3000.
Вказуємо, що цей Proxy публічно доступний.
- Переходимо на вкладку SSL та генеруємо сертифікат.
Вибираємо DNS Challenge та DNS провайдера (Cloudflare/DuckDNS).
Вставляємо API токен Cloudflare або токен DuckDNS.
- Після цього можете включити проксі в Cloudflare.
Налаштування роутера
Залежно від моделі роутера слід шукати налаштування Port Forwarding та додати запис з вхідним портом 443, вихідним портом 443, TCP протокол та IP-адресу nginx.

За необхідності також зарезервуйте IP-адреси в локальній мережі для nginx та doh-server, використовуючи DHCP Reservation. Або самостійно пропишіть IP адреси за межами розподілення DHCP на пристрої(ях) з цими сервісами.

Генеруємо файл для Apple-девайсу
- Створюємо файл doh.mobileconfig.
- Додаємо вміст:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadContent</key> <array> <dict> <key>DNSSettings</key> <dict> <key>DNSProtocol</key> <string>HTTPS</string> <key>ServerURL</key> <string>https://doh.yourdomain.com/dns-query</string> <!-- Вкажіть ваш домен --> </dict> <key>OnDemandRules</key> <array> <dict> <key>Action</key> <string>EvaluateConnection</string> <key>ActionParameters</key> <array> <dict> <key>DomainAction</key> <string> NeverConnect</string> <key>Domains</key> <array> <!-- Додайте домени для ігнорування --> <string>captive.apple.com</string> </array> </dict> </array> </dict> <dict> <key>Action</key> <string>Connect</string> </dict> </array> <key>PayloadDescription</key> <string>Configures device to use Pi-Hole DNS</string> <key>PayloadDisplayName</key> <string>Pi-Hole DoH</string> <key>PayloadIdentifier</key> <string>com.apple.dnsSettings.managed.$(uuidgen)</string> <!-- uuid --> <key>PayloadType</key> <string>com.apple.dnsSettings.managed</string> <key>PayloadUUID</key> <string>$(uuidgen)</string> <!-- uuid --> <key>PayloadVersion</key> <integer>1</integer> </dict> </array> <key>PayloadDescription</key> <string>Adds DoH to macOS Big Sur and iOS 14 or newer systems</string> <key>PayloadDisplayName</key> <string>Pi-Hole DoH</string> <key>PayloadIdentifier</key> <string>$(uuidgen)</string> <!-- uuid --> <key>PayloadRemovalDisallowed</key> <false/> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>$(uuidgen)</string> <!-- uuid --> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>
- Вкажіть свій домен.
- Згенеруйте та вставте рандомні uuid у вказані поля (замість «$(uuidgen)»).
- Також ви можете вказати домени, які ігноруватимуться цим правилом.
Це корисно, якщо використовуєте корпоративний VPN і DNS сервер компанії знаходиться в локальній мережі.
Налаштування macOS
- Відкрийте файл конфігураціїна своєму пристрої та перейдіть в Налаштування -> General -> Device Management, активуйте профіль.

- Перейдіть в Network -> VPN & Filter. Тут ви можете вмикати та вимикати DoH за необхідності.

Налаштування iOS/iPadOS
- Відкрийте файл конфігурації на вашому пристрої. Перейдіть в налаштування -> General -> VPN & Device Management. Активуйте профіль.

- У меню DNS виберіть ваш профіль замість Automatic. В цьому меню ви можете вмикати і вимикати DoH за необхідності.

Таким чином тепер блокування реклами працюватиме в застосунках і не в локальній мережі. Але слід звернути увагу, що під час відключень світла ваш роутер та/або сервер можуть не працювати і, відповідно, не працюватиме DNS-сервер. Ви можете втратити доступ до інтернету через те, що девайс не може визначити IP-адресу за DNS. Тому слід або вимикати DoH, або забезпечити безперебійну роботу обладнання.
Бонус
Ви можете спробувати, як працює DoH, не налаштовуючи власний сервер. Проте не матимете можливості ніяк впливати на фільтри блокування реклами. Існує ініціатива DNS4EU з безкоштовними публічними DNS-серверами. Ви можете завантажити і встановити файл конфігурації з блокуванням реклами від цього сервісу. Інструкція за цим посиланням. Але фільтри там невеликі і більшість реклами залишається.
Також за цим посиланням можна подивитись список різних публічних DNS-серверів. Ви можете спробувати створити власний файл конфігурації і вказати URL.
Використання сторонніх DNS серверів може мати різні наслідки. Враховуйте ці ризики.
Сподобалась стаття автора? Підписуйтесь на його акаунт вгорі сторінки, щоб отримувати сповіщення про нові публікації на пошту.
11 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів