Проект: Finite: блокируем трекеры и ускоряем интернет одной коробочкой  Публичный пост
18 января 2026  90
Finite: блокируем трекеры и ускоряем интернет одной коробочкой
http://github.com/wh1le/finite

Finite: DNS-сервер на Raspberry Pi который убирает рекламу со всех устройств

Я Никита, пишу код на Ruby и JavaScript уже лет десять, в основном финтех и платежи. Сейчас на саббатикале - отдыхаю от работы и ковыряюсь с домашней инфраструктурой.

Почему я вообще этим занялся

Всё началось с телевизора. Купил Samsung, подключил к WiFi, и понял что он показывает рекламу прямо в меню. В меню, Карл! Я заплатил за телевизор, а он мне рекламу крутит.

Ладно, можно пережить. Но потом меня сильно начало доводить другое. Я погуглил кроссовки один раз - и теперь вижу их везде. На телефоне, на ноутбуке, на том же телевизоре в YouTube. Таргетированная реклама следует за мной по всем устройствам.

На компьютере есть AdBlock. На телефоне - с переменным успехом. На телевизоре и умной колонке - никак. Они просто сливают данные о моих запросах куда-то в интернет, и я ничего не могу с этим сделать.

Или могу?

Идея: блокировать рекламу на уровне сети

Если нельзя поставить блокировщик на каждое устройство - можно поставить его на роутер. Точнее, рядом с роутером.

Pi-hole - это штука которая притворяется DNS-сервером. Когда телевизор спрашивает "где находится ads.samsung.com?", Pi-hole отвечает "нигде, такого адреса не существует". Реклама не загружается. Трекер не получает данные.

Это работает для всего что подключено к домашнему WiFi. Телефоны, ноутбуки, телевизоры, умные лампочки - всё проходит через один DNS, и всё фильтруется.

Звучит просто. На практике - неделя боли.

Почему не просто установить Pi-hole по гайду?

Гайдов в интернете миллион. "Установи Raspbian, запусти curl | bash, готово". Я уже так делал очень давно когда впервые начал играться с Raspberry. Работало.

А потом SD-карта умерла. Raspberry Pi любит убивать SD-карты - они не рассчитаны на постоянную запись логов.

Окей, купил новую карту. Сел восстанавливать. И понял что не помню ничего. Какие блоклисты я добавлял? Какой пароль ставил? Как настраивал Unbound? Всё это было в голове год назад, а теперь - чистый лист.

Начал заново. Снова гуглил, снова настраивал, снова забуду через год.

NixOS: вся система в одном файле

На десктопе я уже активно использую NixOS. Это дистрибутив Linux где вся конфигурация системы описана в текстовых файлах. Не "я когда-то запустил команду и что-то установилось", а "вот файл, в нём написано что должно быть
установлено".

Сломал систему? Откатись на предыдущую версию одной командой. Купил новый компьютер? Скопируй конфиг, запусти rebuild, получи идентичную систему.

Подумал - почему бы не сделать то же самое для Raspberry Pi? Один раз написать конфиг, залить в git, и если SD-карта умрёт - пересобрать систему за 5 минут.

Так родился finite.

Что внутри

Скриншот с тестовой конфигурации - 69% блокировки из-за одного агрессивного домена. В реальности за 2 месяца использования держится около 20%.

  • Pi-hole в контейнере - фильтрует DNS запросы по спискам известных рекламных и трекерных доменов
  • Unbound - локальный DNS резолвер, кэширует запросы и шифрует трафик к внешним серверам через DNS-over-TLS
  • Podman вместо Docker - работает без демона, проще интегрируется с systemd
  • Статический IP, SSH только по ключам, минимальный файрвол

Вся конфигурация - один файл settings.nix. Меняешь там свой IP, пароль, часовой пояс. Запускаешь make build_image. Получаешь готовый образ для SD-карты.

Unbound: локальный DNS с кэшированием

Pi-hole блокирует рекламу и кэширует DNS через встроенный dnsmasq. Но есть нюанс - все "хорошие" запросы он пересылает на upstream сервер (обычно Google или Cloudflare). Они видят каждый домен который ты посещаешь.

Unbound решает это. Он умеет работать как recursive resolver - сам ходит к корневым DNS серверам и резолвит домены по цепочке. Плюс шифрует трафик через DNS-over-TLS. Никто не видит полный список твоих запросов.

Бонус - более агрессивное кэширование и prefetch популярных доменов.

Unbound решает это локальным кэшированием. Первый запрос к домену идёт наружу. Все последующие - отдаются из памяти мгновенно.

Вот реальные цифры с моей машины:

# Первый запрос - идёт к внешнему серверу
$ dig github.com @192.168.50.2 | grep "Query time"
;; Query time: 51 msec

# Второй запрос - из кэша
$ dig github.com @192.168.50.2 | grep "Query time"
;; Query time: 5 msec

51ms против 5ms. В десять раз быстрее. Для сайтов которые ты открываешь часто - разница ощутимая.

А вот что происходит когда запрашиваешь заблокированный домен:

$ dig analytics.tiktok.com @192.168.50.2

;; ANSWER SECTION:
analytics.tiktok.com.    2    IN    A    0.0.0.0

;; Query time: 8 msec

Pi-hole возвращает 0.0.0.0 - запрос даже не выходит из локальной сети. Трекер не получает ничего.

Бонус: приватность

Есть ещё один аргумент за локальный Unbound - приватность.

Когда ты используешь DNS от Google, Cloudflare или других напрямую, они видят каждый домен который ты посещаешь. Это в том числе используется для анализа активности в сети и таргета той-же рекалмы.

Unbound умеет работать в режиме recursive resolver - он сам ходит к корневым DNS серверам и резолвит домены по цепочке, не доверяя никому. В finite я настроил компромиссный вариант: Unbound шифрует запросы через DNS-over-TLS к
Cloudflare. Не идеально, но лучше чем plain text DNS который может читать твой провайдер.

Проблема курицы и яйца

Первая версия собралась, записалась на карту, Pi загрузился. Веб-интерфейс Pi-hole открывается. Красота!

Только блоклисты пустые. И статистика нулевая. Ничего не фильтруется.

Два часа дебага. Логи чистые - никаких ошибок. Сервисы запущены. Всё выглядит нормально. Но не работает.

Потом дошло.

Pi-hole при первом запуске должен скачать списки рекламных доменов из интернета. Чтобы что-то скачать из интернета, нужен DNS. Но Pi-hole и есть DNS-сервер. И он настроен использовать сам себя для резолва.

Классическая проблема курицы и яйца. DNS-сервер не может запуститься, потому что ему нужен DNS-сервер.

Решение получилось костыльным: при первой загрузке специальный скрипт временно переключает DNS на Cloudflare, качает блоклисты, и переключает обратно на localhost. Systemd запускает этот скрипт один раз, создаёт файл-метку, и
при следующих загрузках пропускает.

Звучит просто. На практике - час разбирался с порядком запуска сервисов в systemd.

Вторая курица, второе яйцо

Заработало! Блоклисты скачались. Pi-hole фильтрует.

Перезагрузил Pi для проверки. Unbound упал с TLS ошибкой. Сертификат недействителен.

Ещё час дебага. Оказалось - Raspberry Pi не имеет батарейки для часов. При каждой загрузке время сбрасывается на 1 января 1970 года. TLS сертификаты "ещё не действительны", Unbound отказывается работать.

Окей, нужно синхронизировать время через NTP перед запуском Unbound. Но NTP сервер указан по домену time.cloudflare.com. А DNS ещё не работает, потому что Unbound не запустился. Потому что время неправильное. Потому что NTP не
сработал. Потому что DNS не работает.

Опять курица и яйцо!

Решение тупое: захардкодить IP-адреса NTP серверов. 162.159.200.1 вместо time.cloudflare.com. Никакого DNS, просто чистый IP. Работает.

Вывод: всё что должно работать до DNS - указывай по IP-адресам.

Что получилось в итоге

После недели вечеров и ~20 перепрошивок SD-карты - работающая система.

Реклама блокируется на всех устройствах. Samsung перестал показывать баннеры в меню. YouTube на телевизоре стал чище (прероллы всё ещё есть - они приходят с того же домена что и видео, DNS их не отличит).

Статистика за месяц: ~20% запросов с моей сети - к рекламным и трекерным доменам. Все заблокированы.

Железо и затраты

  • Raspberry Pi 4 (4GB) - ~€60
  • SD-карта 32GB - ~€10
  • Ethernet кабель - был
  • Время - неделя вечеров

Про монетизацию

Проект бесплатный и open source под MIT лицензией. Монетизировать не планирую.

Основная аудитория - люди как я 12 лет назад. Которые хотят избавиться от рекламы, имеют Raspberry Pi в ящике, но не хотят разбираться в Linux неделю. Записал образ, воткнул, поменял одну настройку в роутере - работает.

Что дальше

  • Декларативные WhiteList и BlackList домены прямо в конфиге - чтобы не лезть в веб-интерфейс Pi-hole
  • Документация по кастомизации блоклистов
  • Мечта: веб-интерфейс где вводишь настройки, жмёшь кнопку, скачиваешь готовый ISO. Без git, без терминала, без боли.

Вопрос к клубу

Кто ещё ковыряется с домашней инфраструктурой на NixOS?

У меня конкретная проблема с секретами. Пароли лежат в settings.nix, который в .gitignore. Работает, но:

  1. При git pull новых изменений приходится stash'ить локальный конфиг
  2. NixOS ожидает все файлы в репозитории - если файл в gitignore, при сборке на чистой машине его не найдёт

На десктопе использую SOPS, но для finite хочу максимально простую настройку - не заставлять пользователей разбираться с GPG.

Может кто-то решал подобное?

Советы тем кто пойдёт тем же путём

  1. Тестируй с нуля. Проблемы bootstrap появляются только при первой загрузке на чистой системе. Если итерируешь на работающей - никогда их не увидишь.
  2. Всё что до DNS - по IP-адресам. NTP, начальная загрузка данных, healthcheck'и - всё хардкодь.
  3. Тишина - худшая ошибка. Нет логов и ничего не работает? Скорее всего где-то DNS timeout. Он не падает с ошибкой, просто висит и ждёт.
  4. NixOS того стоит. Кривая обучения крутая, но для серверов которые должны "просто работать" - идеально. Один раз настроил, задокументировал в коде, забыл на годы.

GitHub: https://github.com/wh1le/finite

Блог с техническими деталями: https://wh1le.com/finite

Откомментируйте первым 👇

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб