unsubbed.co

blocky

Blocky lets you run fast and lightweight DNS proxy as ad-blocker for local network with many features entirely on your own server.

Network-wide DNS ad-blocking, honestly reviewed. What you get when you replace Pi-hole with a Go binary that fits in 19MB.

TL;DR

  • What it is: A DNS proxy and ad-blocker for local networks, written in Go. Think Pi-hole but stateless, Docker-native, and configurable entirely via a YAML file [2][3].
  • Who it’s for: Homelab operators, self-hosters, and small network admins who want network-wide ad blocking without the Pi-hole complexity. Particularly useful for anyone who wants a config-as-code setup or high availability [2].
  • Cost savings: Commercial DNS filtering services like NextDNS run $1.99–$19.90/mo depending on query volume. Blocky runs free on a Raspberry Pi or a $5 VPS, with no query limits, no telemetry, and no vendor dependency [README][3].
  • Key strength: Stateless architecture. No database, no web UI to maintain, no persistent volumes required. The entire config lives in one YAML file, which makes it trivial to automate, back up, and run as a pair for high availability [2].
  • Key weakness: No built-in web UI. There’s a community project called “Blocky Frontend” but it’s a separate install. If you’re used to Pi-hole’s dashboard showing you query logs with a few clicks, you’ll feel the absence [1].

What is blocky

Blocky is a DNS proxy and ad-blocker for local networks. You point your router (or individual devices) at a blocky instance instead of your ISP’s DNS server. Blocky resolves DNS queries using upstream resolvers of your choice, intercepts queries that match your block lists, and returns a null response for ads, trackers, and malware domains before they ever reach your browser.

The GitHub description says it plainly: “Fast and lightweight DNS proxy as ad-blocker for local network with many features.” That’s accurate and refreshingly unmarketed.

What sets it apart from the obvious alternative, Pi-hole, is the architecture. Blocky is a single Go binary. It has no embedded database, no web interface, no DHCP server, no background jobs writing to disk. Configuration is a single YAML file. The Docker image is under 19MB compressed — compared to Pi-hole’s 107MB Debian-based image [2]. Spin it up, point at it, and it works. Tear it down, no state left behind.

As of this review, the project sits at 6,205 GitHub stars under an Apache-2.0 license. It’s maintained by a single developer (0xERR0R) with community contributions, not a company.


Why people choose it over Pi-hole

The Pi-hole comparison is the one that actually matters for most readers. Pascal Riesinger’s setup article [2] — which is the most detailed operational review available — lays out the case directly:

Pi-hole’s problem is that it wasn’t built for Docker. The Pi-hole image runs a DNS server, hosts a web UI, can run a DHCP server, and manages an embedded database, all inside one container. Configuring blocklists and client groups requires the web interface or CLI commands inside the running container — which means docker exec calls, which means an automation nightmare. Riesinger specifically flags this as his reason for switching [2].

Blocky’s answer is flat-file config. Every setting — upstream resolvers, block lists, per-client group rules, logging, caching behavior — lives in config.yml. You edit a file, restart the container. That’s the entire workflow. This makes Ansible, Terraform, or any infrastructure-as-code approach straightforward, while Pi-hole requires syncing scripts and web UI automation [2].

High availability is trivially achievable. Because blocky is stateless, you can run two identical instances pointing at the same config file and use keepalived or your router’s failover DNS to provide HA. With Pi-hole, getting two synced instances requires third-party scripts like gravity-sync and periodic sync jobs [2]. With blocky, you just run two containers. They’re already identical by definition.

Image size and attack surface matter less than they sound, but they’re still real. The 19MB vs 107MB comparison isn’t about download times — it’s about how much software is installed that can be exploited. Smaller Alpine-based images have less installed attack surface than Debian-based ones [2].

Victor Bayas’ setup guide [3] frames blocky similarly: it’s for people who want a “powerful and versatile DNS proxy” that can be “easily configured with a YAML file.” The guide doesn’t editorialize much, but the implicit message is that blocky is the tool you reach for when you want control over every setting and don’t want a web UI getting between you and the configuration.

What neither article sugarcoats: blocky is more hands-on. Pi-hole has a web dashboard, a large user community, and years of beginner-friendly documentation. Blocky has documentation, but it’s technical documentation. If you’re not comfortable editing YAML and restarting containers, Pi-hole will serve you better.


Features

Blocking:

  • Block lists loaded from external URLs (StevenBlack hosts, domain-specific lists, etc.) with periodic auto-reload [README][1]
  • Per-client-group rules — you can give the kids’ tablet a different block list from the smart TV from the workstation [README][3]
  • Regex support for custom rules [README]
  • Deep CNAME inspection — blocks domains that redirect through an allowed domain to reach a blocked one [README]
  • IP address blocking against IP lists [README]
  • Allowlisting to punch holes in block lists [README][1]

DNS protocol support:

  • Standard DNS over UDP and TCP
  • DNS over HTTPS (DoH) — both as a client to upstream resolvers and as a server endpoint for devices on your network
  • DNS over TLS (DoT) [README][3]
  • DNSSEC validation of upstream resolvers [README]

Performance:

  • Configurable DNS answer caching with TTL control [README][3]
  • Prefetching of frequently queried domains so cache hits are warm before TTL expires [README]
  • Multiple upstream resolvers queried simultaneously — takes the fastest response [README]
  • Low memory footprint; runs comfortably on Raspberry Pi hardware [README][1]

Observability:

  • Prometheus metrics endpoint [README][3]
  • Pre-built Grafana dashboards (for both Prometheus and database backends) [README]
  • Query logging per day per client, in CSV or to MySQL/MariaDB/PostgreSQL/TimescaleDB [README][3]
  • REST API endpoints for runtime queries and control [README]
  • CLI tool for interacting with a running instance [README]

Deployment options:

  • Single binary for direct installation [1]
  • Docker image with multi-arch support (x86-64 and ARM) [README][1]
  • Docker Compose (the practical default for most setups) [1][3]
  • Community-maintained Helm chart for Kubernetes [README][1]
  • TrueNAS SCALE app via TrueCharts catalog [1]
  • AUR package for Arch Linux [1]

What’s missing:

  • No built-in web UI. “Blocky Frontend” exists as a separate community project [1].
  • No DHCP server (intentional — blocky does one thing).
  • No built-in update mechanism for the binary itself.

Pricing: SaaS vs self-hosted math

Blocky has no SaaS tier. It’s free software. The comparison is blocky self-hosted against commercial DNS filtering services:

Commercial DNS filtering alternatives:

  • NextDNS: Free up to 300,000 queries/month; $1.99/mo for unlimited queries on one config; $19.90/mo for teams
  • AdGuard DNS: Free tier with limits; €2.99/mo for Personal (300,000 queries); €8.99/mo for Family
  • Cloudflare Gateway (Teams): Free up to 50 users with basic filtering; paid tiers start at $7/user/mo for advanced features
  • Cisco Umbrella: Enterprise pricing, typically $2–5/user/mo at small business scale

Blocky self-hosted:

  • Software: $0 (Apache-2.0) [README]
  • A Raspberry Pi you already own: $0 marginal cost
  • A $5–6/mo VPS if you don’t want to run hardware at home
  • Your time to configure and maintain it

Concrete math for a household or small office:

A household running NextDNS for a family with multiple devices will hit the 300,000-query free tier limit within a few weeks if multiple people are actively browsing. NextDNS Personal at $1.99/mo is reasonable, but you’re trusting a third party with every DNS query on your network, with no option to run it on your own hardware, point at your own upstream resolvers, or keep query logs private.

Over three years: NextDNS Personal ≈ $72. Blocky on an existing Raspberry Pi ≈ $0. Blocky on a $6 Hetzner VPS ≈ $216 — but that VPS is probably running other services too.

The privacy angle matters as much as the money here. Blocky explicitly does not collect user data, telemetry, or statistics [README]. NextDNS and AdGuard DNS both log queries by default (with options to disable). If your threat model includes not wanting a commercial provider to have a complete record of every DNS lookup from every device on your network, self-hosted is the only real answer.


Deployment reality check

The documentation covers three realistic install paths: binary, Docker, and Kubernetes [1][3].

The practical path for most people is Docker Compose. Victor Bayas’ guide [3] walks through a working docker-compose.yml and config.yml. Pascal Riesinger’s article [2] covers a more advanced setup with HA. Neither describes it as painful — the complexity is in configuring blocky correctly, not in making it run.

What a minimal working config looks like:

upstream:
  default:
    - 46.182.19.48
    - 80.241.218.68
    - tcp-tls:fdns1.dismail.de:853
    - https://dns.digitale-gesellschaft.ch/dns-query
blocking:
  blackLists:
    ads:
      - https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
  clientGroupsBlock:
    default:
      - ads
ports:
  dns: 53
  http: 4000

That’s a working ad-blocking DNS server. It fetches the StevenBlack hosts list on startup, caches it, and blocks matching queries for all clients [1].

What can go sideways:

  • Port 53 on Linux requires elevated privileges. If you’re running blocky as a non-root binary (not Docker), you need to grant CAP_NET_BIND_SERVICE or run as root. The docs are explicit about this [1].
  • Config file syntax errors stop startup cold. If you split config across multiple YAML files (supported for complex setups), duplicate keys across files will cause a startup failure [1]. Test your config before deploying to production.
  • No web UI means no query dashboard out of the box. If you want graphs showing what’s being blocked, you need to set up Prometheus + Grafana, which is an additional setup step. The prepared Grafana dashboards exist [README][3], but you have to wire them up yourself.
  • Block list fetching on startup adds latency to first boot. Large lists like the StevenBlack consolidated hosts file take a few seconds to download and parse. Not a real problem, but don’t expect sub-second container startup.

Realistic time estimates:

  • Technical user comfortable with Docker: 30–45 minutes to a working instance
  • HA setup with two instances and keepalived: add 1–2 hours [2]
  • Prometheus + Grafana observability: another 1–2 hours if you don’t already have the stack running

Pros and Cons

Pros

  • Stateless. No database, no persistent volumes required. Config is one YAML file. Backup is cp config.yml. [2]
  • Genuinely Docker-native. Built for containers from the ground up, not retrofitted. 19MB image, single process, clean startup and shutdown [2].
  • Config-as-code. Every setting is declarative and version-controllable. Ansible, Terraform, or a simple rsync can manage your blocky fleet [2].
  • High availability without syncing scripts. Two identical instances, same config file, any failover mechanism. No gravity-sync equivalent needed [2].
  • Per-client-group policies. Give different devices different block lists. Kids’ tablets, smart home devices, and work machines can each have their own rules [README][3].
  • Modern DNS protocol support. DoH, DoT, DNSSEC — not just legacy UDP/TCP [README].
  • No telemetry. The project explicitly documents that it collects no user data [README].
  • Apache-2.0 license. Permissive. Use it anywhere, embed it, don’t worry about commercial restrictions [README].
  • Runs on Raspberry Pi. ARM support built-in, low memory footprint [README][1].
  • Prometheus + Grafana integration. Pre-built dashboards available for anyone who already has that stack [README][3].

Cons

  • No web UI. Pi-hole’s dashboard is genuinely useful for seeing what’s being blocked in real time. Blocky has an API and CLI, but no graphical interface by default. “Blocky Frontend” is a separate community project with separate installation [1].
  • Single maintainer. This is a personal project, not a company. The 0xERR0R GitHub account is the bus factor. It’s healthy and active, but it’s not backed by a team [README].
  • Steeper learning curve than Pi-hole for non-technical users. If you’re not comfortable with YAML syntax and Docker, Pi-hole’s web-based setup is more accessible.
  • Query log analysis requires setup. CSV logs or database integration are available, but neither is turn-key. Getting useful insight from query logs means setting up Grafana or writing your own queries [README][3].
  • No DHCP. Pi-hole doubles as a DHCP server, which lets it identify clients by hostname and apply per-device rules easily. Blocky identifies clients by IP, which means you need static IPs or DHCP reservations on your router for per-client rules to work reliably [README].
  • Documentation is good but technical. The docs at 0xerr0r.github.io/blocky cover features well, but assume you’re comfortable reading technical documentation rather than following a guided setup wizard.

Who should use this / who shouldn’t

Use blocky if:

  • You’re already running a Docker homelab and want a container-native DNS solution that fits the rest of your stack.
  • You want to manage your ad-blocking config in Git alongside your other infrastructure config.
  • You want high availability without running sync scripts between instances.
  • You care about keeping DNS query data private and not sending it to a third party.
  • You have Prometheus and Grafana running and want to plug DNS metrics into your existing dashboards.
  • You’re running it on a Raspberry Pi or other ARM hardware.

Use Pi-hole instead if:

  • You want a web UI showing real-time query logs without additional setup.
  • You need DHCP integration for easy per-device identification.
  • You’re setting this up for a less technical household member who needs to manage block lists through a browser.
  • You want the largest beginner-friendly community and the most forum answers when something breaks.

Use a commercial service (NextDNS, AdGuard DNS) instead if:

  • You don’t want to maintain any self-hosted infrastructure.
  • You need filtering that follows devices off your home network (commercial services work anywhere; blocky only works when devices use it as their resolver).
  • You’re not comfortable with YAML and Docker.

Alternatives worth considering

  • Pi-hole — the obvious alternative. More features for non-technical users (web UI, DHCP, guided setup), worse fit for Docker-native and HA setups. Larger community, more beginner resources.
  • AdGuard Home — closer to Pi-hole than blocky in terms of having a polished web UI and guided setup. Open source, also Docker-deployable, with more active commercial backing behind it.
  • Unbound — a full recursive DNS resolver rather than a forwarding proxy. More complex, more control. Often combined with Pi-hole or blocky rather than used standalone.
  • CoreDNS — Kubernetes-native DNS server. More infrastructure-focused, plugin-based architecture, not built for ad-blocking but can do it. Better choice if you’re running k8s and want DNS in the cluster.
  • NextDNS — commercial managed service. No infrastructure to maintain, works off-network, $1.99/mo. Right choice if you want zero maintenance.
  • Technitium DNS Server — another self-hosted option with a web UI, more configuration options than Pi-hole, less known than either Pi-hole or blocky.

Bottom line

Blocky solves a specific problem well: network-wide DNS ad-blocking that fits into a modern container infrastructure without compromise. If you’re building a homelab or small network setup with Docker, want config-as-code, and can live without a web dashboard, blocky is a cleaner choice than Pi-hole in nearly every dimension — smaller image, stateless, HA-ready, fully automatable. The trade-off is real: no web UI, single maintainer, steeper initial learning curve. But for the reader who already manages infrastructure and just wants their DNS layer to behave like the rest of their stack — declarative, version-controlled, restartable without ceremony — blocky is the right tool. A $5 VPS and a 30-minute config session replaces a commercial DNS filtering subscription that also sends every query to a third party.

If you need someone to handle the deployment, that’s exactly what upready.dev does for clients. One-time setup, you own the infrastructure.


Sources

  1. Installation — blocky documentation · 0xerr0r.github.io · https://0xerr0r.github.io/blocky/v0.22/installation/
  2. Pascal Riesinger — “My Highly Available DNS setup with Blocky” · riesinger.dev · https://riesinger.dev/posts/ha-dns-adblocking-with-blocky/
  3. Victor Bayas — “How to setup Blocky DNS ad blocker on Docker” · victorbayas.com · https://victorbayas.com/posts/blocky-adblock-docker-setup

Primary sources:

Features

Integrations & APIs

  • Plugin / Extension System
  • REST API

Analytics & Reporting

  • Metrics & KPIs

Security & Privacy

  • SSL / TLS / HTTPS