Blocky: a stateless DNS proxy for per-client-group filtering
Fast and lightweight DNS proxy as ad-blocker for local network with many features
At a glance
- What is it?
- Blocky is a Go DNS proxy that resolves, caches and filters queries on your own network, with allow and deny lists scoped to named client groups. The interesting design choice is that it stores no state: your filtering rules and your query history live in YAML and in an external database you point it at.
- Who is it for?
- Adopt Blocky if you already run your own DNS and want filtering rules that differ per client group, and you are willing to keep the YAML in version control. Skip it if you want a web UI to click through, or if you cannot own a resolver that sits in front of every query on the network.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem: one DNS server, several kinds of client
A home or small-office network rarely has one uniform class of device. There are laptops belonging to adults, tablets belonging to children, smart-home plugs that should reach a vendor cloud and nothing else, and whatever guests bring in. A single blocklist applied to the whole network cannot express that. Either you block aggressively and break the smart plugs, or you block conservatively and the parental controls do nothing. The README frames this directly: Blocky supports the "definition of allow/denylists per client group (Kids, Smart home devices, etc.)", and upstream resolvers can be defined per client group as well. That second part matters more than it first appears. A client group is not just a filter set, it is a routing decision. You can send the kids' devices to a filtering resolver and a work laptop to a resolver that returns the real answer for a domain your blocklist would otherwise swallow. The intended audience is someone who already administers the network: a homelab operator, a small business running its own resolver, or anyone who would otherwise be configuring a Pi-hole. Blocky assumes you are comfortable writing YAML and reading a log, and it does not pretend otherwise.
What actually happens to a query
Blocky is a proxy, not an authoritative server. A client points its DNS at Blocky, and Blocky decides what to do with the name before it ever leaves the network. The README lists the decision points: the request domain itself, the CNAME in the response (described as deep CNAME inspection), and the IP addresses in the response checked against IP lists. That ordering is the mechanism. A domain can pass the request-stage check and still be blocked later, because the CNAME it resolves to, or the address it finally returns, appears on a list. This is why Blocky catches some trackers that a simple hostname blocklist misses, and it is also why a block can appear in the log against a domain you never added. Resolution itself goes out over one of the supported transports: DNS over UDP and TCP, DNS over HTTPS, DNS over TLS, DNS over QUIC (RFC 9250), and DNS over HTTPS/3 (RFC 9114). The README states that Blocky uses random upstream resolvers from the configuration, which distributes queries across providers rather than pinning every lookup to one. Caching sits in front of that, with prefetching of frequently used queries, so repeat lookups do not leave the network at all. On the inbound side Blocky can also expose a DoH endpoint, which means a roaming client can use Blocky as its resolver without a VPN.
Stateless by design, and what that costs you
The README calls Blocky stateless: no database, no temporary files. Configuration is one or more YAML files. That is a real operational property, not a slogan. Backing up the service means copying a file. Moving it to another host means copying the same file. There is no volume to migrate and no schema to upgrade. The cost is that anything you want to remember has to be remembered elsewhere. Query logging is written per day and per client, either to CSV or to MySQL, MariaDB, PostgreSQL or Timescale. Blocky writes to that database; it does not treat it as its own state store. If the database is unreachable, the DNS path is unaffected, which is the right failure ordering for a resolver sitting in front of every device on the network. The same pattern applies to observability: Prometheus metrics are exposed and the project ships prepared Grafana dashboards for both the Prometheus and the database backends. So the honest description is that Blocky is stateless in the sense that matters for availability, and stateful only in the sense that you supply a sink for its logs. Anyone expecting Blocky to keep its own history and show it in a UI will be disappointed.
Getting it running: the YAML is the product
The README's quick start does not give a command sequence; it points to the Installation chapter of the documentation at 0xerr0r.github.io/blocky. What the repository does tell you is the shape of deployment: a single binary, a multi-arch Docker image published as spx01/blocky, and support for x86-64, ARM and MIPS, which is what makes a Raspberry Pi or an OpenWrt router a realistic target. There is also a community-supported Helm chart for Kubernetes, and the README is explicit that it is community supported rather than maintained by the project. Configuration is YAML, and it is where the actual work happens: allow and deny lists, the client groups those lists attach to, upstream resolvers per group, and the transport settings for each upstream. The README also notes that external allow and deny lists are reloaded periodically, so a URL-backed blocklist refreshes without a restart. Regex is supported in list entries. A CLI tool ships alongside the server, and various REST API endpoints are exposed. Because the documentation lives outside this repository, treat the config file as the thing you must read end to end before trusting a deployment. A DNS resolver that starts successfully with a misconfigured client group will simply filter the wrong devices, and nothing in the log will tell you that you meant something else.
Where Blocky is the wrong tool
Blocky is a network-level control. It sees a query and the client address that sent it, and nothing more. If a device uses its own encrypted resolver, or an application resolves through a hardcoded DoH endpoint, Blocky never sees the query and cannot block it. That is a property of DNS filtering generally, but it matters when you are choosing: the per-client-group model only works for clients you actually control the resolver settings on. The second limitation is the interface. The README describes YAML files, REST endpoints, CSV or SQL logging and Grafana dashboards. There is no mention of a built-in web admin UI. If you want to add a domain to an allowlist from a phone while standing in the kitchen, Blocky expects you to edit YAML and reload, or call the API. That is a deliberate trade: a config file is diffable and reviewable, a web UI is not. Third, the project is maintained by one person in their spare time, as the README states in its support section, and it asks for contributions. That is not a reason to avoid it, but it is a reason to pin a version and read release notes before upgrading, because there is no vendor behind it. Finally, the stateless design means there is no rollback of configuration built in. Your YAML in version control is your rollback.
How it differs from Pi-hole
The obvious comparison is Pi-hole, and both projects appear in Blocky's own topic list. The difference is in where the configuration lives and how filtering is scoped. Pi-hole's model is a web interface backed by a local database, with blocklists and per-client settings managed through that UI. Blocky's model is a YAML file with no local database, where client groups are a first-class part of the configuration and upstream resolvers can be assigned per group. That second capability is the clearest divergence: in Blocky, routing a group to a different upstream is a configuration line, not a separate mechanism. The transport support also differs in emphasis. Blocky's README lists DoQ (RFC 9250) and DoH3 (RFC 9114) among the supported protocols, which puts it ahead of tools that only speak plain DNS or DoH. The trade is convenience for auditability. If you want a dashboard with a block-percentage chart and a button to add a domain, Pi-hole is built around that workflow. If you want the entire filtering policy to be a text file you can review in a pull request and deploy with a container restart, Blocky is built around that one.
Licence, maintenance and what a version bump costs you
Blocky is Apache-2.0. That is a permissive licence: you can run it commercially, modify it, and redistribute it, provided you keep the licence and notice files and state your changes. It includes an explicit patent grant, which is the main practical difference from MIT. It does not require you to publish your configuration, and it does not oblige you to contribute changes back. This is a description of the licence text, not legal advice; check the terms yourself if you are embedding Blocky in a product. On maintenance, the release cadence visible in the repository is roughly monthly, with v0.33.0 in late June, v0.34.0 in late July, and v0.35.0 in early September. The version numbers are still below 1.0, which the project's own numbering implies: interfaces and configuration keys can change between minor releases. The upgrade path is short because there is no database migration and no persistent state, so a version bump is a binary or image swap plus a config review. The config review is the part that costs time. Read the release notes for the versions you skip, diff your YAML against the current documentation, and keep a known-good copy so a rollback is a file copy rather than a rebuild.
Editorial conclusion
Adopt Blocky if you already run your own DNS and want filtering rules that differ per client group, and you are willing to keep the YAML in version control. Skip it if you want a web UI to click through, or if you cannot own a resolver that sits in front of every query on the network. Before you commit, verify three things on your own hardware: that the blocky binary or container starts with your config and passes config validation, that your upstream resolvers answer over the protocol you chose (DoH, DoT, DoQ or DoH3), and that your client-group definitions actually match the clients you expect, since a group that matches nothing fails silently rather than loudly.
Community notes