🧭 Decision Guide
Why trending now: The README highlights a $2 ESP32-C3, 537k domains, about 50 KB of RAM, and roughly 10 ms matching, and lists coverage by Tom's Hardware, XDA Developers, and Korben. Combined with 196 new stars today, the material supports that low-cost hardware hosting a large DNS list is driving attention.
Try it if you
-
You have a 4 MB ESP32-C3 SuperMini and want to run the roughly 100k default blocklist without PSRAM.README sections Hardware and Build & flash (PlatformIO): C3 SuperMini, 4 MB flash, no PSRAM, and a default list of about 100k entries.
-
You need to place the DNS blocker on a router USB port and can accept roughly 10 ms hash lookup latency.README sections Hardware and Why this is interesting: a USB-A → USB-C dongle can connect it to a router, and lookup takes about 10 ms.
-
You want to flash over USB once, then maintain the blocklist and firmware through c3adblock.local.README sections Build & flash (PlatformIO) and Over-the-air updates: firmware and blocklist can both be updated over WiFi afterward.
Skip it if you
-
You must use the 537k ultimate list and firmware OTA on hardware with only 4 MB of flash.README section Over-the-air updates: OTA needs two app slots and limits the blocklist to about 250k; the 537k list requires the single-app partition table.
-
Your threat model includes LAN traffic sniffing and requires an encrypted management interface.README section Security: all traffic uses plain HTTP on :80, and Basic Auth credentials are sent as base64 rather than encrypted.
-
You plan to expose the device to an untrusted network or run with the default CHANGE_ME credentials.README section Security: the default credentials are public, and the project explicitly describes Basic Auth as a LAN-trust-boundary control.
-
You only have an old apt PlatformIO package such as 4.3.4.README section Build & flash (PlatformIO): the distro/apt PlatformIO package, such as 4.3.4, fails with AttributeError: ... 'resultcallback'.
Requirements
- An ESP32-C3 board, tested on a C3 SuperMini, with 4 MB flash and no PSRAM needed
- A stable USB source, such as a phone charger or router's USB port
- Current PlatformIO; the README says apt PlatformIO 4.3.4 is too old
- Configure WEB_USER, WEB_PASS, and OTA_PASS in src/secrets.h first
- The first USB flash requires pio run -t upload and pio run -t uploadfs
First step (verbatim from README)
cp src/secrets.example.h src/secrets.h
Watch out
-
Cheap or loose USB-C→A adapters can cause a brownout during WiFi transmission.README section Hardware: cheap/loose USB-C→A adapters can brown out the radio during WiFi transmit.
-
With unchanged secrets.h, the device still boots but logs a warning and shows a public-password banner.README section Security: CHANGE_ME_WEB_PASSWORD and CHANGE_ME_OTA_PASSWORD trigger a warning, but the firmware still runs.
-
The C3-AdBlock-XXXX WiFi setup access point remains open and unencrypted.README section Security: the setup portal access point is still open (unencrypted) by design.
-
Custom /addblock domains are HTML-escaped, but network OTA still requires OTA_PASS.README section Security: custom names are HTML-escaped, and ArduinoOTA requires OTA_PASS.
Alternatives
-
Traditional ESP32 + PSRAM DNS sinkhole:It is better when you need to keep domain strings directly in RAM or can accept ESP32 + PSRAM hardware costing about $8.README section Why this is interesting
Not stated in the README
- The README does not specify concurrent DNS query volume or throughput limits during long-term operation.
- The README does not specify the default upstream resolver, timeout, or retry behavior.
- The README does not provide complete flashing commands for the 537k ultimate list under each partition table.
- The README omits the detailed Enclosure, Gotchas, and Done / how it could grow sections.
- The README does not provide a per-model compatibility list for ESP32-C3 boards beyond the C3 SuperMini.
💡 Deep Analysis
6
It depends
I need the Web dashboard, blocklist upload, and firmware OTA on a home LAN. Is the security boundary sufficient if the device still uses HTTP Basic Auth and an open setup AP?
It depends: it is acceptable on a trusted home LAN, but not on public WiFi, an exposed network, or a LAN with potential traffic sniffers.
- The README’s Security section requires
WEB_USER/WEB_PASSfor state-changing endpoints,OTA_PASSfor network OTA, and the customX-Requested-With: c3-adblockheader to reduce common CSRF attacks. - However, the dashboard is plain HTTP on port 80 and Basic Auth is only Base64. The README explicitly says open/guest WiFi, ARP spoofing, or an on-path sniffer can read credentials.
- If
CHANGE_ME_WEB_PASSWORDorCHANGE_ME_OTA_PASSWORDremains in place, the public placeholder values from the example file still work. TheC3-AdBlock-XXXXsetup AP is also intentionally open and unencrypted. - The security model is therefore “trusted-LAN protection against ordinary unauthenticated API access,” not TLS or public-facing administration security.
- README, “Security”: mutating endpoints require HTTP Basic Auth; OTA requires `OTA_PASS`; `X-Requested-With: c3-adblock` is required
- README, “Security”: everything is plain HTTP on port 80 and Basic Auth credentials are Base64
- README, “Security”: default placeholder passwords are public and the WiFi setup AP remains open and unencrypted
Yes
I need to handle 141k to 537k domains on a no-PSRAM ESP32-C3 while controlling RAM and lookup latency. Is a 40-bit FNV-1a hash table with Flash binary search suitable?
Yes, because it is designed specifically around the RAM and Flash limits of a no-PSRAM device, but you must accept the possibility of false blocking from hash collisions.
- The README says domains are converted into sorted 40-bit hashes stored in Flash; more than 141k domains use about 0.7 MB, with roughly 50 KB of RAM at runtime.
- The device computes FNV-1a, checks parent suffixes, and binary-searches the Flash table. The README cites about 18 Flash reads and roughly 10 ms including WiFi RTT.
- Its collision estimate is about zero at 141k domains and about one at 537k, making 40 bits a tradeoff among storage, lookup cost, and false-blocking risk rather than a collision-free guarantee.
- The bucketed prefix index is still marked incomplete and aims to reduce about 18 reads to 1–2; that improvement is not part of the current implementation.
- README, “Why this is interesting”: sorted 40-bit hashes in Flash, about 50 KB RAM, and 141,000+ domains in about 0.7 MB
- README, “Why 40 bits?”: about zero collisions at 141k and about one at 537k
- README, “Done / how it could grow”: bucketed prefix index is unchecked, with a target of reducing about 18 reads to 1–2
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
No
I want all home and small-office clients to use the ESP32-C3 for DNS-based ad blocking. Does it meet my requirements if the device briefly loses power or clients use DoH/DoT?
No, it is not suitable as the sole, non-bypassable DNS infrastructure because device outages can affect resolution and encrypted DNS can bypass it.
- The project insight identifies the ESP32 as a single point of failure: power loss, WiFi interruption, firmware faults, or Flash damage can affect dependent DNS clients, so a fallback is needed when it is the only DNS server.
- The README’s “Use it” only requires clients to point DNS at the device or use it as a secondary resolver; automatic DHCP DNS distribution is not provided, and acting as a DHCP server is still an unchecked item.
- The project insight states that DoH/DoT, hard-coded IPs, or alternate DNS paths can bypass UDP-DNS filtering. The implementation only sinkholes matches and forwards misses.
- It is therefore better suited to home, small-office, and experimental networks as an auxiliary resolver than as an enterprise enforcement point.
- README, “Done / how it could grow”: “Act as the DHCP server” remains unchecked
- README, “Use it”: point a device’s DNS at the C3’s IP or add it as a secondary resolver
- Project insight, usage_limitations: DoH/DoT, hard-coded IPs, caches, or alternate DNS can bypass filtering; the ESP32 is a single point of failure
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
No
I only have a 4 MB-flash, no-PSRAM ESP32-C3 SuperMini. Can I use this project with about 537k domains while keeping firmware OTA?
No, not for both goals at once: a 4 MB Flash layout cannot hold the largest list and a standard firmware OTA layout simultaneously.
- The project targets an ESP32-C3 without PSRAM; 40-bit hashes store about 537k domains in Flash while using about 50 KB of RAM.
- The project data states that enabling dual application partitions for firmware OTA leaves about 1.3 MB for the blocklist, limiting it to roughly 250k domains. The roughly 537k-domain list requires a single-application layout.
- You therefore have to trade coverage for remote firmware maintenance: keep OTA with a smaller list, or use the larger list and retain a USB recovery path.
The README does not provide the complete PlatformIO partition definitions, so the exact capacity of a custom layout is unknown.
- README, “Why this is interesting”: 537,000 domains, 40-bit hashes, and about 50 KB RAM
- Project insight, common_pitfalls: dual-app OTA on 4 MB Flash leaves about 1.3 MB for the blocklist, or roughly 250k domains
- Project insight, best_practices: the largest blocklist requires a larger blocklist partition and a USB recovery path
Yes
I only have a roughly $2 no-PSRAM ESP32-C3 and want to plug it into my router’s USB port for home ad blocking. Is this project more suitable operationally than a Raspberry Pi setup?
Yes, it suits a home deployment focused on low cost, small size, and no separate server, but it still requires PlatformIO, USB flashing, and router DNS configuration skills.
- The README explicitly describes a roughly $2, no-PSRAM ESP32-C3 Pi-hole-style DNS ad blocker; a USB-A-to-USB-C dongle can plug it into a spare USB port on many routers.
- If WiFi cannot connect or
secrets.his not configured, it starts the openC3-AdBlock-XXXXAP and captive portal, so initial WiFi setup does not require reflashing. - It includes a Web dashboard, statistics, manual bans, custom domains, blocklist updates, and firmware OTA, shortening maintenance compared with repeated USB reflashing.
- The tradeoff is that deployment is not fully plug-and-play: the README still requires pointing client DNS at the device, and stable power matters because cheap or loose USB-C adapters can cause brownouts during WiFi transmission.
- README opening: Pi-hole-style DNS ad blocker on a $2 ESP32-C3 with no PSRAM required
- README, “Hardware”: USB-A-to-USB-C dongle can plug into many router USB ports; stable USB source is required
- README, “WiFi setup”: failure to connect starts the `C3-AdBlock-XXXX` captive portal
- README, “Done / how it could grow”: Web dashboard, OTA, and scheduled remote blocklist pulls are complete
dig @<c3-ip> doubleclick.net # -> 0.0.0.0 (blocked)
It depends
My board is not the primary tested ESP32-C3 but a 4 MB-flash Classic ESP32 DevKit/WROOM. Can I use this project directly as my home-network DNS?
It depends: Classic ESP32 builds are supported, but the ESP32-C3 is the primary test target, and effective home DNS blocking depends on clients actually sending queries to the device.
- The README’s Hardware section says Classic ESP32 DevKit/WROOM boards with 4 MB can build and gives
pio run -e esp32dev -t upload; it also says this is community-contributed and compile-tested, while the C3 is the tested target. - The architecture returns 0.0.0.0 for blocked domains and forwards misses to an upstream resolver, providing both sinkholing and normal DNS resolution.
- Use requires pointing clients at the device IP or placing it as a secondary resolver behind the main DNS. DoH/DoT, hard-coded DNS, or alternate resolvers can bypass filtering.
The README does not specify Classic ESP32 latency, maximum list size, or long-term stability.
- README, “Hardware”: Classic ESP32 DevKit/WROOM, 4 MB, builds with `pio run -e esp32dev -t upload`; the C3 is the tested target
- README, “Use it”: point a device’s DNS at the C3’s IP or add it as a secondary resolver
- README flow diagram: hits return 0.0.0.0 and misses are forwarded to the upstream resolver
pio run -e esp32dev -t upload
✨ Highlights
-
Runs a 537k-domain list on an ESP32-C3 without PSRAM
-
40-bit FNV-1a hashes use about 50 KB of RAM
-
Flash binary search matches DNS queries in about 10 ms
-
With OTA enabled, 4 MB flash limits the list to about 250k domains
🔧 Engineering
-
The ESP32-C3 uses a UDP DNS sinkhole to block domains and forward misses
-
PlatformIO flashes firmware and blocklist.bin, with WiFi OTA updates afterward
-
http://c3adblock.local provides DNS stats, list upload, and firmware OTA
⚠️ Risks
-
HTTP Basic Auth protects endpoints over plain HTTP :80 and does not provide TLS
-
The two-app partition required for OTA limits blocklist capacity to about 250k on 4 MB flash
-
At 537k domains, 40-bit hashes are expected to have one collision and may over-block a domain
-
Leaving CHANGE_ME passwords in secrets.h exposes the LAN interface with public credentials
👥 For who?
-
Home-network developers with a 4 MB ESP32-C3 SuperMini using PlatformIO
-
Embedded developers needing to host the roughly 100k default list without PSRAM
-
Network users wanting a lightweight DNS secondary resolver for blocking