
© 2025 DE KOKER Guillaume.
During my project of rationalizing and isolating my home network infrastructure from my lab (a project that should never have been needed… don’t put your lab in prod :D), i wanted to upgrade my router from Pfsense to Opnsense.
This forced me to drop Pfsense very flexible pfblockerNG
and i migrated to a small Pi Hole instance on my lab K8s
. This only moved the issue, because i still need my lab to be up and running if i want DNS filtering to work… And i wanted to avoid running another computer with K8s
on prod.
I went for AdGuard home, running directly on Opnsense, but after the first-time setup. i realize that the blacklist and whitelist will be a real pain to move… So i decided to make a tool for myself :D
You can find my python script on this github page. It make copy pasting easier, but doesn’t directly build the AdGuard home config file since i wanted to use the GUI.
First thing first, you will need to export your current Pi Hole config.
For this, login to your Pi hole, and go to Settings
, then Teleporter
.
Finish by Clicking the Backup
button and download the tar.gz
file.
Now that you have your backup file, let’s extract the data we need. First, download and the script from this github page and put it in a folder. I recommend that you make a python venv, but there are not many library needed and your system properly already have them all.
Place your Pi Hole backup archive in the same folder, and run the script like so:
Python3 convert_config.py pi-hole-XXX-teleporter_XXX.tar.gz
The script will work for a bit, as it check all if any of your blacklist no-longer exist, before returning with something like this.
Add each of the following blocklist to the DNS blocklists page:
Name: Migrated from /etc/pihole/adlists.list
URL: https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
Name: EasyList Feeds - Utilizing only the domains which are listed to be blocked in full.
URL: https://easylist-downloads.adblockplus.org/easylist_noelemhide.txt
Name: EasyList Feeds - Utilizing only the domains which are listed to be blocked in full.
URL: https://easylist-downloads.adblockplus.org/easyprivacy.txt
Name: ADs - Collection of ADvertisement Domain Feeds.
URL: https://adaway.org/hosts.txt
Name: ADs - Collection of ADvertisement Domain Feeds.
URL: http://sysctl.org/cameleon/hosts
Name: ADs - Collection of ADvertisement Domain Feeds.
URL: https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt
Name: ADs - Collection of ADvertisement Domain Feeds.
URL: https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt
Name: ADs - Collection of ADvertisement Domain Feeds.
URL: https://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml
Name: Malicious - Collection of Malicious Domain Feeds.
URL: https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt
[...]
Copy past this in the Custom filtering rules field:
! Whitelist
# anudeepND/whitelist
@@|t.co^
# Added from Audit Log
@@|twitter.com^
# Added from Query Log
@@|laposte.net^
# None
@@|youtube.com^
# None
@@|s.shopify.com^
# anudeepND/whitelist
@@|cdn.optimizely.com^
# None
@@|split.io^
# None
@@|t.ly^
# None
@@|www.bit.ly^
# None
@@|bit.ly^
# None
@@|ow.ly^
# anudeepND/whitelist
@@|tinyurl.com^
# anudeepND/whitelist
@@|0.client-channel.google.com^
# anudeepND/whitelist
@@|1drv.com^
# anudeepND/whitelist
@@|2.android.pool.ntp.org^
# anudeepND/whitelist
@@|akamaihd.net^
# anudeepND/whitelist
[...]
! Blacklist
# New google nonesical extention
/(\.|^)zip$/
# Polyfill supply chain attack
/(\.|^)polyfill\.io$/
# Polyfill supply chain attack
/(\.|^)bootcdn\.net$/
# Polyfill supply chain attack
/(\.|^)bootcss\.com$/
# Polyfill supply chain attack
/(\.|^)staticfile\.net$/
# Polyfill supply chain attack
/(\.|^)staticfile\.org$/
# Polyfill supply chain attack
/(\.|^)unionadjs\.com$/
# Polyfill supply chain attack
/(\.|^)xhsbpza\.com$/
# Polyfill supply chain attack
/(\.|^)union\.macoms\.la$/
# Polyfill supply chain attack
/(\.|^)newcrbpc\.com$/
Now that you have the output of the script, it’s pretty easy to import it all into AdGuard home.
First the blacklist. Go to Filters
, DNS blocklists
and for each couple of line in the first section of the script output, click Add blocklist
, Add Custom list
, and copy-past the name and url into the field.
Finally, for the url and domain white and black list, go to Filters
, Custom filtering rules
and copy-past everything under Copy past this in the Custom filtering rules field:
in the empty text-block.
When i was migrating to AdGuard, i wanted to keep the same design principal. My main DNS is and should stay Unbound DNS from Opnsense, and only some device should go through AdGuard. So a DNS request from a protected device basically do:
Device ─────► AdGuard ─────► Unbound
But now that AdGuard in on the router, it can reach every network, and because of this i was getting some DNS error where the device rejected the response since it didn’t come from the right port.
reply from unexpected source: 192.168.42.254#3053, expected 192.168.42.254#53
The tricks was to force AdGuard to only listen to 127.0.0.1, forcing it to route all traffic through the router.
Using SSH, Connect to your router and edit /usr/local/AdGuardHome/AdGuardHome.yaml
Near the top of the file, you should find the DNS section.
...
dns:
bind_hosts:
- 127.0.0.1 <-- Here replace 0.0.0.0 by this
port: 3053
...
now simple create a Port Forwarding rule like this in Opnsense to have everything work together !