Blocky is a self-hosted DNS proxy replacing cloud resolvers like NextDNS with local ad-blocking, YAML-based configuration, and native Prometheus metrics.
NextDNS centralizes resolver logs on third-party servers and enforces monthly query quotas once traffic scales beyond personal allowances. Blocky relocates that entire resolution pipeline to a self-hosted proxy inside the local network perimeter. It enforces client-specific blocklists and conditional upstreams directly from static YAML configuration without transmitting network telemetry outward.
NextDNS delivers managed cloud filtering with zero infrastructure overhead, but that model requires trusting an external provider with every internal device lookup. Home devices, automation controllers, and personal workstations continuously dispatch DNS queries that map daily habits and online activity. When using cloud resolvers, those query streams leave the local subnet, and features like custom retention or extended logs require recurring subscription fees.
Blocky reverses that dynamic by treating DNS as local infrastructure defined in code. Running as a single Go binary or lightweight container, it intercepts network queries, validates upstream signatures over DNS-over-HTTPS or DNS-over-QUIC, and strips unwanted domains before requests reach external networks. You surrender NextDNS's turnkey setup and managed web dashboard in exchange for complete data sovereignty, unmetered query volume, and the ability to declare client groups, IP blocking rules, and upstream routes in revision-controlled configuration files.
Blocky vs NextDNS — which should I choose? NextDNS fits users who want zero-maintenance filtering across roaming mobile devices. Blocky fits homelabs prioritizing total data privacy, local resolution speed, and code-based configuration without subscription fees.
Does Blocky include a web interface for managing blocklists? No, Blocky relies on YAML files and a REST API rather than an integrated web interface. Monitoring query traffic requires exporting metrics to Prometheus and Grafana.
Can Blocky run alongside an existing local DHCP server? Yes, Blocky uses conditional upstream forwarding to route queries for local hostnames and reverse lookups back to your existing router or DHCP server.
Blocky is an ideal choice for homelab engineers who treat network services as code and want lightweight, redundant DNS ad-blocking without transmitting lookups to external cloud platforms; it is unsuited for users seeking a turnkey web interface or native mobile profile management. Active development with commits through late August 2026 and an Apache-2.0 license—granting freedom to deploy or package the binary within custom infrastructure—make it a dependable alternative to commercial cloud resolvers.
Commands from the official package registries. Each package is matched to Blocky through the registry's own link to its source code or website.
brew install blockybrew install blockyWe started this exact setup from scratch in a clean Linux machine on Nov 2, 2026 and checked it through Blocky's own API: every check passed. Recipes are re-checked regularly and removed if they stop working.
mkdir -p blocky && cd blocky
curl -fsSL https://open-source.store/tools/blocky/compose.yml -o compose.ymlcat > .env <<EOF
TZ=UTC
EOFTZ — Timezone for Blocky log timestamps and statistics.docker compose up -dservices:
blocky:
image: ghcr.io/0xerr0r/blocky:v0.35.0
restart: always
ports:
- "127.0.0.1:4000:4000"
- "53:53/udp"
environment:
TZ: ${TZ}
volumes:
- blocky-cache:/app/cache
configs:
- source: blocky_config
target: /app/config.yml
healthcheck:
test: ["CMD", "/app/blocky", "healthcheck"]
interval: 5s
timeout: 3s
retries: 5
configs:
blocky_config:
content: |
upstreams:
groups:
default:
- 1.1.1.1
- 8.8.8.8
customDNS:
customTTL: 1h
mapping:
oss-test.internal: 192.168.1.100
blocking:
loading:
strategy: fast
downloads:
cachePath: /app/cache
denylists:
ads:
- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
clientGroupsBlock:
default:
- ads
ports:
dns: 53
http: 4000
volumes:
blocky-cache: {}
Go, gRPC and Protobuf done right, LLM agents in production, and the hard parts of shipping a first product.
Show that Blocky is listed as an open-source alternative. Paste into your README:
Ubuntu 24.04 · Apple container, Docker 29.1.3, Compose 2.40.3+ds1-0ubuntu1~24.04.1. Images pulled in 165 s: ghcr.io/0xerr0r/blocky:v0.35.0.
Based on the upstream setup. Official Docker setup from Blocky documentation. Image pinned to v0.35.0; HTTP API port 4000 bound to 127.0.0.1 because Blocky has no built-in HTTP authentication; DNS port 53 (UDP) published; configuration provided via compose configs and cache persisted in a named volume.
blocky-1 | 2026-11-02T22:28:14.085033253Z [2026-11-02 22:28:14] INFO _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ blocky-1 | 2026-11-02T22:28:14.085048587Z [2026-11-02 22:28:14] INFO _/ _/ blocky-1 | 2026-11-02T22:28:14.085049753Z [2026-11-02 22:28:14] INFO _/ _/ blocky-1 | 2026-11-02T22:28:14.085050378Z [2026-11-02 22:28:14] INFO _/ _/ _/ _/ _/ blocky-1 | 2026-11-02T22:28:14.085050962Z [2026-11-02 22:28:14] INFO _/ _/_/_/ _/ _/_/ _/_/_/ _/ _/ _/ _/ _/ blocky-1 | 2026-11-02T22:28:14.085051503Z [2026-11-02 22:28:14] INFO _/ _/ _/ _/ _/ _/ _/ _/_/ _/ _/ _/ blocky-1 | 2026-11-02T22:28:14.085052045Z [2026-11-02 22:28:14] INFO _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ blocky-1 | 2026-11-02T22:28:14.085052545Z [2026-11-02 22:28:14] INFO _/ _/_/_/ _/ _/_/ _/_/_/ _/ _/ _/_/_/ _/ blocky-1 | 2026-11-02T22:28:14.085053087Z [2026-11-02 22:28:14] INFO _/ _/ _/ blocky-1 | 2026-11-02T22:28:14.085053628Z [2026-11-02 22:28:14] INFO _/ _/_/ _/ blocky-1 | 2026-11-02T22:28:14.085054170Z [2026-11-02 22:28:14] INFO _/ _/ blocky-1 | 2026-11-02T22:28:14.085054712Z [2026-11-02 22:28:14] INFO _/ _/ blocky-1 | 2026-11-02T22:28:14.085055212Z [2026-11-02 22:28:14] INFO _/ Version: v0.35.0 Build time: 20260905-163623 _/ blocky-1 | 2026-11-02T22:28:14.085055795Z [2026-11-02 22:28:14] INFO _/ _/ blocky-1 | 2026-11-02T22:28:14.085056337Z [2026-11-02 22:28:14] INFO _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ blocky-1 | 2026-11-02T22:28:14.085336795Z [2026-11-02 22:28:14] INFO bootstrap: bootstrapDns is not configured, will use system resolver blocky-1 | 2026-11-02T22:28:16.678441546Z [2026-11-02 22:28:16] INFO server: current configuration: blocky-1 | 2026-11-02T22:28:16.678487463Z [2026-11-02 22:28:16] INFO server: -> query_logging: blocky-1 | 2026-11-02T22:28:16.678491254Z [2026-11-02 22:28:16] INFO server: type: console blocky-1 | 2026-11-02T22:28:16.678493046Z [2026-11-02 22:28:16] INFO server: logRetentionDays: 0 blocky-1 | 2026-11-02T22:28:16.678494629Z [2026-11-02 22:28:16] INFO server: flushInterval: 30 seconds blocky-1 | 2026-11-02T22:28:16.678496254Z [2026-11-02 22:28:16] INFO server: fields: [clientIP clientName responseReason responseAnswer question duration] blocky-1 | 2026-11-02T22:28:16.678497629Z [2026-11-02 22:28:16] INFO server: ignore: blocky-1 | 2026-11-02T22:28:16.678499379Z [2026-11-02 22:28:16] INFO server: sudn: false blocky-1 | 2026-11-02T22:28:16.678500671Z [2026-11-02 22:28:16] INFO server: -> custom_dns: blocky-1 | 2026-11-02T22:28:16.678501921Z [2026-11-02 22:28:16] INFO server: mapping: blocky-1 | 2026-11-02T22:28:16.678503171Z [2026-11-02 22:28:16] INFO server: oss-test.internal = [ 3600 CLASS0 None 192.168.1.100] blocky-1 | 2026-11-02T22:28:16.678529671Z [2026-11-02 22:28:16] INFO server: -> blocking: blocky-1 | 2026-11-02T22:28:16.678531629Z [2026-11-02 22:28:16] INFO server: clientGroupsBlock: blocky-1 | 2026-11-02T22:28:16.678533004Z [2026-11-02 22:28:16] INFO server: default = [ads] blocky-1 | 2026-11-02T22:28:16.678534463Z [2026-11-02 22:28:16] INFO server: blockType = ZEROIP blocky-1 | 2026-11-02T22:28:16.678535879Z [2026-11-02 22:28:16] INFO server: blockTTL = 6 hours blocky-1 | 2026-11-02T22:28:16.678537129Z [2026-11-02 22:28:16] INFO server: loading: blocky-1 | 2026-11-02T22:28:16.678538338Z [2026-11-02 22:28:16] INFO server: concurrency = 4 blocky-1 | 2026-11-02T22:28:16.678539546Z [2026-11-02 22:28:16] INFO server: refresh = every 4 hours blocky-1 | 2026-11-02T22:28:16.678540796Z [2026-11-02 22:28:16] INFO server: downloads: blocky-1 | 2026-11-02T22:28:16.678542046Z [2026-11-02 22:28:16] INFO server: timeout = 5 seconds blocky-1 | 2026-11-02T22:28:16.678543296Z [2026-11-02 22:28:16] INFO server: attempts = 3 blocky-1 | 2026-11-02T22:28:16.678544504Z [2026-11-02 22:28:16] INFO server: cachePath = /app/cache blocky-1 | 2026-11-02T22:28:16.678545796Z [2026-11-02 22:28:16] INFO server: denylists: blocky-1 | 2026-11-02T22:28:16.678547046Z [2026-11-02 22:28:16] INFO server: ads: blocky-1 | 2026-11-02T22:28:16.678548296Z [2026-11-02 22:28:16] INFO server: - https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts blocky-1 | 2026-11-02T22:28:16.678549713Z [2026-11-02 22:28:16] INFO server: allowlists: blocky-1 | 2026-11-02T22:28:16.678550921Z [2026-11-02 22:28:16] INFO server: denylist cache entries: blocky-1 | 2026-11-02T22:28:16.678552171Z [2026-11-02 22:28:16] INFO server: ads: 0 entries blocky-1 | 2026-11-02T22:28:16.678553379Z [2026-11-02 22:28:16] INFO server: TOTAL: 0 entries blocky-1 | 2026-11-02T22:28:16.678554588Z [2026-11-02 22:28:16] INFO server: allowlist cache entries: blocky-1 | 2026-11-02T22:28:16.678555921Z [2026-11-02 22:28:16] INFO server: TOTAL: 0 entries blocky-1 | 2026-11-02T22:28:16.678559213Z [2026-11-02 22:28:16] INFO server: -> caching: blocky-1 | 2026-11-02T22:28:16.678560504Z [2026-11-02 22:28:16] INFO server: minTime = 0 seconds blocky-1 | 2026-11-02T22:28:16.678561754Z [2026-11-02 22:28:16] INFO server: maxTime = 0 seconds blocky-1 | 2026-11-02T22:28:16.678562963Z [2026-11-02 22:28:16] INFO server: cacheTimeNegative = 30 minutes blocky-1 | 2026-11-02T22:28:16.678564213Z [2026-11-02 22:28:16] INFO server: exclude: blocky-1 | 2026-11-02T22:28:16.678565421Z [2026-11-02 22:28:16] INFO server: cache entries = 0 blocky-1 | 2026-11-02T22:28:16.678566629Z [2026-11-02 22:28:16] INFO server: -> special_use_domains: blocky-1 | 2026-11-02T22:28:16.678567963Z [2026-11-02 22:28:16] INFO server: -> parallel_best: blocky-1 | 2026-11-02T22:28:16.678569171Z [2026-11-02 22:28:16] INFO server: group: default blocky-1 | 2026-11-02T22:28:16.678570421Z [2026-11-02 22:28:16] INFO server: upstreams: blocky-1 | 2026-11-02T22:28:16.678583963Z [2026-11-02 22:28:16] INFO server: - tcp+udp:1.1.1.1 blocky-1 | 2026-11-02T22:28:16.678586046Z [2026-11-02 22:28:16] INFO server: - tcp+udp:8.8.8.8 blocky-1 | 2026-11-02T22:28:16.678587338Z [2026-11-02 22:28:16] INFO server: listeners: blocky-1 | 2026-11-02T22:28:16.678588546Z [2026-11-02 22:28:16] INFO server: DNS = [:53] blocky-1 | 2026-11-02T22:28:16.678589754Z [2026-11-02 22:28:16] INFO server: TLS = [] blocky-1 | 2026-11-02T22:28:16.678591004Z [2026-11-02 22:28:16] INFO server: HTTP = [:4000] blocky-1 | 2026-11-02T22:28:16.678592296Z [2026-11-02 22:28:16] INFO server: HTTPS = [] blocky-1 | 2026-11-02T22:28:16.678593463Z [2026-11-02 22:28:16] INFO server: DOHPath = /dns-query blocky-1 | 2026-11-02T22:28:16.678594713Z [2026-11-02 22:28:16] INFO server: FreeBind = false blocky-1 | 2026-11-02T22:28:16.678595879Z [2026-11-02 22:28:16] INFO server: PROXY protocol = [] blocky-1 | 2026-11-02T22:28:16.678597088Z [2026-11-02 22:28:16] INFO server: runtime information: blocky-1 | 2026-11-02T22:28:16.682759671Z [2026-11-02 22:28:16] INFO server: numCPU = 2 blocky-1 | 2026-11-02T22:28:16.682789713Z [2026-11-02 22:28:16] INFO server: numGoroutine = 20 blocky-1 | 2026-11-02T22:28:16.683147004Z [2026-11-02 22:28:16] INFO server: memory: blocky-1 | 2026-11-02T22:28:16.683153504Z [2026-11-02 22:28:16] INFO server: heap = 2 MB blocky-1 | 2026-11-02T22:28:16.683155296Z [2026-11-02 22:28:16] INFO server: sys = 17 MB blocky-1 | 2026-11-02T22:28:16.683156838Z [2026-11-02 22:28:16] INFO server: numGC = 6 blocky-1 | 2026-11-02T22:28:16.683158338Z [2026-11-02 22:28:16] INFO server: Starting server blocky-1 | 2026-11-02T22:28:16.683449296Z [2026-11-02 22:28:16] INFO server: UDP server is up and running on address :53 blocky-1 | 2026-11-02T22:28:16.683583213Z [2026-11-02 22:28:16] INFO server: TCP server is up and running on address :53 blocky-1 | 2026-11-02T22:28:16.683655838Z [2026-11-02 22:28:16] INFO server: http server is up and running on addr/port [::]:4000 blocky-1 | 2026-11-02T22:28:16.688788713Z [2026-11-02 22:28:16] INFO disable blocking for group(s) 'ads; default' blocky-1 | 2026-11-02T22:28:16.691417004Z [2026-11-02 22:28:16] INFO queryLog: query resolved answer=A (192.168.1.100) client_ip=172.18.0.1 client_names=172.18.0.1 instance=c94481421c8e question_name=oss-test.internal. question_type=A response_code=NOERROR response_reason=CUSTOM DNS response_type=CUSTOMDNS blocky-1 | 2026-11-02T22:28:20.587065340Z [2026-11-02 22:28:20] INFO list_cache: import succeeded count=77772 source=https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts blocky-1 | 2026-11-02T22:28:20.591247673Z [2026-11-02 22:28:20] INFO list_cache: group import finished group=ads total_count=77770