Open-source project
s60sc/ESP32_AdBlocker avatar
s60sc/ESP32_AdBlocker

ESP32_AdBlocker puts a DNS sinkhole on a five dollar board

ESP32 based DNS sinkhole for ads and trackers

529 stars61 forksC++AGPL-3.0

At a glance

What is it?
ESP32_AdBlocker is an Arduino sketch that answers 0.0.0.0 for every domain in a blocklist and forwards the rest to an external resolver, so a single ESP32 can filter ads and trackers for a whole network. It works, but only with PSRAM, only over IPv4, and only if clients stop using secure DNS.
Who is it for?
ESP32_AdBlocker fits a household that wants a self-contained, low power DNS filter with a web page to manage it and no separate server to maintain. It does not fit a network where clients insist on IPv6 DNS or where encrypted DNS is enforced by policy, because the device has no IPv6 address and browsers bypass adapter settings when Use secure DNS is on.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A sinkhole small enough to live on the network shelf

Pi-hole is the usual answer to household ad blocking, but it wants a host with a spare processor and a place to run a daemon. ESP32_AdBlocker takes a different approach: a single ESP32 board becomes a DNS sinkhole for the entire network, answering 0.0.0.0 for any domain name that appears in its blocklist and passing everything else to an external DNS server to resolve. Because the lookup never leaves the device, content is neither retrieved from nor sent to a blocked domain, which is the whole mechanism in one sentence.

The audience is people with an existing wired or wireless network who want blocking without an always-on server, without accounts and without a subscription. A board that draws little power and sits on the network shelf fits that brief better than a mini PC does. The project also targets ESP32 hardware with an attached SD card, since the application pulls its web interface files onto the card, and the code is written as a C++ Arduino sketch.

A web server is bundled into the firmware to control the service and to monitor it, which is the key ergonomic decision. There is no separate admin tool and no command line to learn. The README frames the device as working like Pi-hole in spirit, and the repository topics carry the same comparison alongside ad-blocker and pi-hole terms.

PSRAM size is the real hardware constraint

The requirement stated up front is blunt: the ESP32 module needs PSRAM. The amount of PSRAM decides how large a blocklist you can run and how fast a lookup is, and the documentation gives concrete figures for two hardware configurations.

An ESP32-S3 with 8MB PSRAM can host a currently sized blocklist, and blocklist checks take less than 50 micro seconds. A plain ESP32 with 4MB PSRAM may truncate a currently sized blocklist, and its checks take less than 100 micro seconds. Truncation is the important word there. On the 4MB part you are not getting the same protection, you are getting a prefix of it, and the documentation does not say which prefix, so the effective coverage depends on the order of the list file you supply.

That makes hardware selection part of the configuration decision rather than an afterthought. If you plan to load a large consolidated list, the S3 with 8MB is the part the project actually targets. The compile step asks for PSRAM to be enabled and for a specific partition scheme, which ties back to the same constraint from the build side: an ESP32-S3 is built with the `8M with spiffs (...)` partition scheme and a plain ESP32 with `Minimal SPIFFS (...)`.

One list file, one daily download, and a local custom list

The data flow is deliberately narrow. After power up, the default blocklist is downloaded, and the device needs several minutes to process and sort the data before it is ready. Progress is visible on the web page. Later reloads of the same file are described as much quicker, since only the updates need to be processed, and the ESP32-S3 is called about twice as fast as the ESP32 for this work.

There is a constraint worth pausing on: only one file can be downloaded, so a consolidated blocklist should be used, ideally smaller than the size of the PSRAM. The file format can be HOSTS format or Adblock format, and in the Adblock case only domain name entries are processed. The project points at the StevenBlack hosts repository as a source of suitable files, and expects you to paste the URL of the file you want into the web page.

After that first load, the device downloads the selected file daily at a given time to keep the list fresh. On top of the remote list sits a local custom blocklist where you can add or remove individual domains yourself. Those personal entries are what the AddDomain, DelDomain and CheckDomain buttons act on, and the page reports the result of each action with an alert message.

The web page is the entire control surface

Every function of the device is exposed as entries on a single web page, and the naming is direct enough that you can use it without a manual. Two counters sit at the top: allowed domains, the number of domain requests permitted since restart, and blocked domains, the number blocked since restart. Below them sits the current URL for the blocklist file, so you always know which list is live.

The input box for a new blocklist URL drives the main operations. Entering a URL and pressing Reload downloads that file, while leaving the field blank reloads the current blocklist instead. The buttons StopLoad and Clear custom blocklist cover the two recovery cases you are most likely to need: interrupting a download that is taking too long, and wiping your own additions when they start causing problems.

The rest of the configuration lives under the Edit Config tab. The Network section holds additional network and webserver settings, and two fields matter most: the router IP address, used to obtain a static IP, and the static IP address itself, which becomes the DNS server address you hand out to clients. The Settings section holds environmental settings affecting blocklist operation, including the LED pin. The Ethernet section selects the network to use and, for Ethernet boards, defines the SPI pin numbers wired to the external Ethernet controller. Pressing Save makes changes persistent. Log messages are visible on a Show Log tab, where a Verbose button adds a line for every blocked or accepted connection.

Pointing a router at it, and the IPv6 trap behind it

To make the device your preferred DNS server, you enter its IPv4 address in place of the current DNS server IPs in your router or on individual devices. The device has no IPv6 address, and since some devices prefer IPv6 by default, the documentation says to disable IPv6 DNS on the device or router so that IPv4 DNS is used.

On a Windows PC the sequence is a command prompt change to the adapter settings. With the board at 192.168.1.168, the DNS server on the Wi-Fi adapter is set with:

bash
netsh interface ip set dns "Wi-Fi" static 192.168.1.168

To go back to a public resolver, the same command points the adapter at 8.8.8.8:

bash
netsh interface ip set dns "Wi-Fi" static 8.8.8.8

The same reasoning applies to routers and phones, where you set the LAN DNS option instead of using per-device commands.

One browser setting undoes all of that work: browsers must have Use secure DNS disabled, because that feature overrides adapter and router DNS settings. On a shared household network this is the failure mode that produces a mystery, because a phone can appear to ignore the sinkhole entirely while the device itself is working correctly. Anyone who knows about DoH can bypass a DNS filter that way, which is a property of the technique rather than a defect in this implementation.

First flash, access point setup and OTA updates

Installation starts as an Arduino sketch rather than a packaged build. The project says to download the GitHub files into the Arduino IDE sketch folder, removing the `-main` suffix from the application folder name. Compilation requires the esp32 arduino core at version v3.1.1 or later, with PSRAM enabled and the partition scheme chosen to match the board.

On the first run the sketch starts in WiFi access point mode. You connect to the SSID beginning ESP32_AdBlocker and open the web page at 192.168.4.1 to enter the router and password details. The configuration data file is then created automatically, and, once an internet connection exists, the application web pages are downloaded from GitHub into the /data folder on the SD card.

Updates take two routes. Application updates, and updates to the /data folder files, can be pushed with the OTA Upload tab. The /data folder can also be reloaded from GitHub with the Reload /data button on the Edit Config tab, or with a WebDAV client, and the repository contains a webDav.cpp source file to match. The SD card requirement is not optional in practice, since that is where the interface files live.

Ethernet support is narrow, and the LED tells you where it stands

WiFi is the default interface, with Ethernet offered as an alternative on boards with built-in Ethernet or through an external controller. The documentation is candid about the limits of that path: the feature is only tested for a W5500 Ethernet controller connected to an ESP32-S3 board. Three network options are listed. WiFi is the default and also the fallback if Ethernet cannot be connected. Eth+AP runs Ethernet plus the ESP access point, with the warning that you should not open web pages on both networks at once. Ethernet uses the controller alone, with no WiFi at all.

The LED provides the quickest status readout, and the code supports both a simple LED and a W2812 RGB LED. For the simple version, access point mode is a slow blink, active is steady, offline is a very slow blink, failure is a fast blink and downloading hosts is a medium blink. The RGB version adds colour: slow blink yellow in access point mode, steady green when active, very slow blink teal when offline, fast blink red on failure, medium blink blue while downloading hosts, and flashing purple when a hosts download is attempted without an internet connection. The pin is set through the Settings button on the Edit Config tab, and setting the LED pin value to 0 disables the light.

The last push to the repository was on 2026-10-17, with tagged releases v3.7 on 2026-10-10, v3.6 on 2026-10-08 and v3.5 on 2026-09-20. Version 3.7 lists enhancements to DNS query handling and the LED status, a timezone fix, and fixes contributed by two users. The project is licensed AGPL-3.0, which carries obligations if you modify the firmware and serve it over a network, so read the LICENSE file before building a modified version for others to use.

Editorial conclusion

ESP32_AdBlocker fits a household that wants a self-contained, low power DNS filter with a web page to manage it and no separate server to maintain. It does not fit a network where clients insist on IPv6 DNS or where encrypted DNS is enforced by policy, because the device has no IPv6 address and browsers bypass adapter settings when Use secure DNS is on. Before committing, check that your board carries PSRAM of the size listed, confirm the blocklist file you plan to point it at fits that memory, and set a static IP in the Edit Config tab so the router keeps using the same resolver address.

Frequently asked questions

What hardware does ESP32_AdBlocker need to run a blocklist?

The ESP32 module needs PSRAM. An ESP32-S3 with 8MB PSRAM can host a currently sized blocklist and checks take less than 50 micro seconds, while an ESP32 with 4MB PSRAM may truncate that list and checks take less than 100 micro seconds.

How do I point ESP32_AdBlocker at a blocklist file?

Paste the URL of a single HOSTS format or Adblock format file into the blocklist URL field on the web page and press Reload. Only one file can be downloaded, so the list should be consolidated and ideally smaller than the size of the PSRAM.

Why do some devices still show ads when ESP32_AdBlocker is running?

Browsers must have Use secure DNS disabled, since that option overrides adapter and router DNS settings. The ESP32_AdBlocker device also has no IPv6 address, so IPv6 DNS has to be disabled on the client or router to force traffic through its IPv4 address.

Can ESP32_AdBlocker use Ethernet instead of WiFi?

Yes, on boards with built-in Ethernet or with an external controller, and the option is selected in the Ethernet section of the Edit Config tab along with the SPI pin numbers used by the controller. The feature is only tested for a W5500 Ethernet controller connected to an ESP32-S3 board.

How are ESP32_AdBlocker updates applied after the first installation?

Application updates and /data folder files can be pushed with the OTA Upload tab, and the /data folder can be reloaded from GitHub with the Reload /data button on the Edit Config tab or with a WebDAV client.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. README
  4. Releases
  5. s60sc/ESP32_AdBlocker on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/s60sc-esp32-adblocker.svg)](https://hysenlabs.com/projects/s60sc-esp32-adblocker)

Was this useful?