Plan: Migrate dns-ad-blocker to Blocky
Status
State: Active Started: 2026-05-14
Context
The current dns-ad-blocker service uses oznu/dns-ad-blocker:latest. This image is critically outdated:
- Last image build: ~2020 (5+ years old)
- Repository status: Archived by owner on April 30, 2022 (read-only)
- Security risk: Running unmaintained base OS, outdated dnsmasq/dnscrypt-proxy binaries, no upstream CVE patches
- Tag risk: Uses
:latestrolling tag with no actual updates
The service provides network-wide DNS resolution with ad blocking for the 192.168.2.0/24 LAN via port 53 on 192.168.2.151.
Sepia uses dnsmasq on the host for DHCP (not handled by the container). The dns-ad-blocker container handles DNS resolution and ad blocking only.
Current Architecture
LAN clients → dnsmasq (host, port 53, DHCP)
│
▼ /etc/resolv.conf → dns-ad-blocker or upstream
Proposed: Blocky
Image: ghcr.io/0xerr0r/blocky:v0.25 (or latest stable)
Repository: https://github.com/0xERR0R/blocky
Why: Stateless (config-as-code), single Go binary (lightweight), native DoH/DoT, built-in Prometheus metrics, no mandatory web UI, actively maintained.
Blocky fits sepia's infrastructure philosophy — config-as-code, lightweight, metrics-native.
Goals
- [ ] Create Blocky config with equivalent ad-blocking, whitelist, and upstream DNS
- [ ] Create Blocky compose file
- [ ] Test Blocky alongside existing dns-ad-blocker
- [ ] Cut over: stop dns-ad-blocker, start Blocky
- [ ] Update docs (services.md, network.md, caddy.md)
- [ ] Clean up old dns-ad-blocker files after stability period
Steps
Step 1: Create Blocky Config
Create /opt/blocky/config.yml:
upstream:
default:
- 1.1.1.1
- 1.0.0.1
blocking:
blackLists:
ads:
- https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
- https://someonewhocares.org/hosts/zero/hosts
whiteLists:
ads:
- api.segment.io
- www.googleapis.com
- analytics.google.com
clientGroupsBlock:
default:
- ads
blockType: zeroIp
caching:
minTime: 5m
maxTime: 30m
prefetching: true
prometheus:
enable: true
path: /metrics
ports:
dns: 53
http: 4000
log:
level: info
Whitelist notes: Current whitelist from dns-ad-blocker includes api.segment.io, www.googleapis.com, analytics.google.com. Custom rules from custom.conf need review — these may include Google ad service bypass rules that should also be in the whitelist.
- Verification:
touch /opt/blocky/config.yml && docker run --rm -v /opt/blocky/config.yml:/app/config.yml:ro ghcr.io/0xerr0r/blocky:v0.25 --validate-configpasses
Step 2: Create Blocky Compose File
Create /opt/compose.blocky.yaml:
services:
blocky:
image: ghcr.io/0xerr0r/blocky:v0.25
container_name: blocky
ports:
- 192.168.2.151:53:53/tcp
- 192.168.2.151:53:53/udp
- 4000:4000/tcp
environment:
- TZ=Europe/Amsterdam
volumes:
- /opt/blocky/config.yml:/app/config.yml:ro
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
Bind to 192.168.2.151 on port 53 (same IP as the current dns-ad-blocker gets via network alias).
- Verification:
docker compose -f compose.blocky.yaml configvalidates
Step 3: Test Blocky Alongside
Deploy Blocky while dns-ad-blocker is still running:
# Stop dns-ad-blocker briefly to free port 53
docker compose -f compose.dns-ad-blocker.yaml down
# Start Blocky
docker compose -f compose.blocky.yaml up -d
# Test resolution
dig @192.168.2.151 google.com
dig @192.168.2.151 doubleclick.net # should return 0.0.0.0
Test cases: - Regular DNS resolution works (google.com, github.com) - Ad domains return 0.0.0.0 (doubleclick.net, adservice.google.com) - Whitelisted domains resolve normally (api.segment.io) - LAN hostnames resolve (veenboer.xyz local services)
- Verification: All test cases pass
Step 4: Update Compose Includes
Edit /opt/compose.yaml:
- Remove compose.dns-ad-blocker.yaml from includes
- Add compose.blocky.yaml
docker compose up -d blocky
docker compose ps # verify blocky is healthy
- Verification:
dig @192.168.2.151 google.comresolves from LAN clients
Step 5: Cleanup (After 2-Week Stability)
- [ ] Remove
/opt/compose.dns-ad-blocker.yaml - [ ] Remove
/opt/dns-ad-blocker/directory - [ ] Remove old dnsmasq config files in that directory
- [ ] Update
REFERENCE/services.md— replace entry - [ ] Update
REFERENCE/network.md— update port 53 mapping - [ ] Update
REFERENCE/caddy.md— if any caddy routes reference it - [ ] Add cleanup reminder to
HEARTBEAT.md(2 weeks)
Rollback
If issues arise within 2 weeks:
# Stop Blocky
docker compose -f compose.blocky.yaml down
# Restore old dns-ad-blocker
docker compose -f compose.dns-ad-blocker.yaml up -d
# Revert compose.yaml includes
git checkout compose.yaml
Related
- PLANS/active/infrastructure-hardening.md (healthcheck for dns-ad-blocker is deferred to this plan)
- REFERENCE/services.md
- REFERENCE/network.md
- REFERENCE/caddy.md
Created: 2026-05-14