rimubhai_
PortfolioBlogsComponentsAbout

© 2026 rimubhai_ All rights reserved.

AboutGalleryContactPrivacy
BlogCyber Security
Cyber Security

Build a Network-Wide Ad Blocker from Scratch

The Master Guide: Build a Network-Wide Ad Blocker from Scratch If you're exhausted by popup ads, invasive tracking scripts, and video commercials slowing down y…

rimubhai
Aug 1, 20269 min read9 sections

The Master Guide: Build a Network-Wide Ad Blocker from Scratch

If you're exhausted by popup ads, invasive tracking scripts, and video commercials slowing down your Wi-Fi, you’re in the right place.

Browser extensions are great for your laptop, but they can't help your smart TV, your phone apps, or your smart home devices. The ultimate solution is to block these ads at the source—before they ever reach your devices.

In this guide, we are going to build a network-wide ad blocker (Pi-hole). We’ll host it on a Fedora Linux machine, and then we’ll configure your Tenda router so that every single device in your house automatically uses it.

Even if you have never touched Linux or a terminal before, don't worry. I've broken this down into simple, copy-and-paste steps. If you follow along carefully, you'll have a blazing-fast, ad-free network in about 15 minutes.

Let’s dive in.

The Game Plan

Here is exactly what we are going to do:

  1. Gather our tools: Install the necessary software on your machine.

  2. Prep the host: Run a script that configures Fedora's(I'm using) network ports and sets up Pi-hole.

  3. Automate the router: Create a Python script that physically logs into your router and updates the settings for you.

  4. Turn it on: Execute the scripts and set up your admin dashboard.

  5. Plug the leaks: Tweak your phone/browser settings so they don't bypass your new blocker.

  6. Block anything: Learn how to nuke specific sites (like TikTok) from your entire home.

Part 1: Install the Required Tools

First, we need to install the background engines that will run our ad blocker and automate our router.

Open your Fedora terminal (press the Windows / Super key, type Terminal, and press Enter).

Copy the block of text below, paste it into your terminal, and press Enter. It will ask for your computer's password.

Bash: I'm using Fedora, so I'll show exactly what I did.

# 1. Update Fedora's software list and install Podman (to run Pi-hole) and Python Pip
sudo dnf install -y podman python3-pip

# 2. Install Playwright (a tool that lets Python click buttons on web pages)
pip install playwright

# 3. Download the automated Chromium browser for Playwright to use
python3 -m playwright install chromium

Why are we installing this? Podman is Fedora's native, lightweight engine for running background apps like Pi-hole. Python and Playwright will be used later to act as a "ghost user" that logs into your router and changes the settings for you!

Part 2: Create the Setup Script (deploy_pihole.sh)

By default, your Fedora computer uses a specific "door" (Port 53) for its own internet routing. Pi-hole needs to use that exact same door to listen to your whole network.

Instead of making you type out twenty different commands to fix this, open the firewall, and configure Pi-hole, I've bundled it all into one script.

In your terminal, copy and paste this entire block and hit Enter. It will create a file named deploy_pihole.sh:

Bash

cat << 'EOF' > deploy_pihole.sh
#!/usr/bin/env bash
set -euo pipefail

echo "[INFO] Starting Pi-hole deployment on Fedora Workstation..."

# 1. Check Root Privileges
if [[ $EUID -ne 0 ]]; then
    echo "[ERROR] This script must be run as root or with sudo."
    exit 1
fi

# 2. Detect Fedora Host Static IP
HOST_IP=$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')
if [[ -z "$HOST_IP" ]]; then
    HOST_IP=$(hostname -I | awk '{print $1}')
fi
echo "[INFO] Detected Host IP Address: ${HOST_IP}"

# 3. Reconfigure systemd-resolved to release Port 53
echo "[INFO] Reconfiguring systemd-resolved drop-in..."
mkdir -p /etc/systemd/resolved.conf.d

cat << 'RESOLV_EOF' > /etc/systemd/resolved.conf.d/pihole.conf
[Resolve]
DNS=1.1.1.1 8.8.8.8
DNSStubListener=no
RESOLV_EOF

# Update /etc/resolv.conf symlink
rm -f /etc/resolv.conf
echo "nameserver 1.1.1.1" > /etc/resolv.conf
echo "nameserver 8.8.8.8" >> /etc/resolv.conf

# Restart systemd-resolved
systemctl restart systemd-resolved
echo "[SUCCESS] systemd-resolved reconfigured."

# 4. Open Firewalld Ports
echo "[INFO] Configuring firewalld rules..."
if ! systemctl is-active --quiet firewalld; then
    systemctl enable --now firewalld
fi

firewall-cmd --permanent --add-port=80/tcp || true
firewall-cmd --permanent --add-port=53/tcp || true
firewall-cmd --permanent --add-port=53/udp || true
firewall-cmd --reload
echo "[SUCCESS] Firewalld rules updated."

# 5. Create Podman Quadlet Service Definition
echo "[INFO] Registering Podman Quadlet container..."
mkdir -p /etc/containers/systemd
mkdir -p /etc/pihole /etc/dnsmasq.d

cat << QUADLET_EOF > /etc/containers/systemd/pihole.container
[Unit]
Description=Pi-hole DNS Ad Blocker Container
After=network-online.target systemd-resolved.service
Wants=network-online.target

[Container]
Image=docker.io/pihole/pihole:latest
ContainerName=pihole
Environment=TZ=UTC
Environment=FTLCONF_LOCAL_IPV4=${HOST_IP}
Environment=PIHOLE_DNS_=1.1.1.1;1.0.0.1
Volume=/etc/pihole:/etc/pihole:Z
Volume=/etc/dnsmasq.d:/etc/dnsmasq.d:Z
PublishPort=53:53/tcp
PublishPort=53:53/udp
PublishPort=80:80/tcp
Network=host

[Service]
Restart=always
TimeoutStartSec=300

[Install]
WantedBy=multi-user.target default.target
QUADLET_EOF

# 6. Start Pi-hole Service via Systemd
echo "[INFO] Reloading systemd daemon and starting pihole service..."
systemctl daemon-reload
systemctl start pihole

echo "=================================================================="
echo "[SUCCESS] PI-HOLE DEPLOYED SUCCESSFULLY!"
echo " Web Admin URL:   http://${HOST_IP}/admin"
echo " Primary DNS IP:  ${HOST_IP}"
echo "=================================================================="
EOF

chmod +x deploy_pihole.sh

Part 3: Create the Router Automation Script (tenda_dns_updater.py)

For Pi-hole to work, your Tenda router needs to tell every phone and laptop in your house to use the Fedora machine for DNS lookups. Normally, you'd have to log into your router, dig through the settings, and type this in manually.

Instead, this Python script uses Playwright to open an invisible browser, log into your router's web portal, find the exact setting, type in your Fedora computer's IP address, and hit save.

Copy and paste this into your terminal:

Bash

cat << 'EOF' > tenda_dns_updater.py
#!/usr/bin/env python3
import argparse
import sys
import time
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger("TendaUpdater")

def update_router(router_ip, password, pihole_ip):
    from playwright.sync_api import sync_playwright
    url = f"http://{router_ip}"
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page(viewport={"width": 1280, "height": 800})
        
        logger.info(f"Connecting to Tenda Router at {url}...")
        page.goto(url, wait_until="domcontentloaded", timeout=15000)
        page.wait_for_timeout(3000)
        
        # 1. Login
        pwd_sel = 'input[placeholder="Login Password"]'
        if page.is_visible(pwd_sel, timeout=3000):
            page.fill(pwd_sel, password)
            page.click('button:has-text("Login")')
            page.wait_for_timeout(4000)
            logger.info("Logged into Tenda router successfully.")
            
        def get_contexts():
            ctxs = [page]
            for f in page.frames:
                if f != page:
                    ctxs.append(f)
            return ctxs

        # 2. Navigate to Administration / LAN Parameters
        menu_items = ['text="Administration"', 'text="Advanced"', 'text="Internet Settings"']
        dns_input = None
        target_ctx = None

        for m in menu_items:
            try:
                if page.is_visible(m, timeout=2000):
                    page.click(m)
                    page.wait_for_timeout(3000)
            except Exception:
                continue

            for ctx in get_contexts():
                for sel in ['#sys_dns1', '#preferredDns', '#dns1', '#lanDns1', 'input[name*="dns" i]']:
                    try:
                        if ctx.is_visible(sel, timeout=1000):
                            dns_input = sel
                            target_ctx = ctx
                            break
                    except Exception:
                        continue
                if not dns_input:
                    try:
                        loc = ctx.locator('tr:has-text("Preferred DNS") input, div:has-text("Preferred DNS") input').first
                        if loc.is_visible(timeout=1000):
                            dns_input = loc
                            target_ctx = ctx
                            break
                    except Exception:
                        continue
                if dns_input:
                    break
            if dns_input:
                break

        if not dns_input or not target_ctx:
            logger.error("Could not find Preferred DNS field on router web page.")
            browser.close()
            return False

        # 3. Update DNS Field
        logger.info(f"Setting Preferred DNS to {pihole_ip}...")
        if isinstance(dns_input, str):
            target_ctx.fill(dns_input, "")
            target_ctx.fill(dns_input, pihole_ip)
        else:
            dns_input.fill("")
            dns_input.fill(pihole_ip)

        # 4. Click Save
        for save_btn in ['#submit', '#save', 'button:has-text("Save")', 'input[value="Save"]']:
            try:
                if target_ctx.is_visible(save_btn, timeout=1000):
                    target_ctx.click(save_btn)
                    logger.info("Saved router DNS configuration.")
                    break
            except Exception:
                continue

        page.wait_for_timeout(4000)
        browser.close()
        return True

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--router-ip", default="192.168.0.1")
    parser.add_argument("--password", default="admin")
    parser.add_argument("--pihole-ip", required=True)
    args = parser.parse_args()

    if update_router(args.router_ip, args.password, args.pihole_ip):
        logger.info("[SUCCESS] Tenda router Primary DNS updated to Pi-hole!")
        sys.exit(0)
    else:
        logger.error("[FAILURE] Could not auto-update router DNS. Please configure manually.")
        sys.exit(1)
EOF

Part 4: Let's Fire It All Up!

You now have the tools and the scripts. It's time to actually run them. Just run these three commands one by one.

1. Run the host setup script:

Bash

sudo bash deploy_pihole.sh

(You will see a bunch of text fly by, ending with a green success message showing your Fedora IP address).

2. Create your dashboard password:

You need a password to view your network statistics. Run this command (feel free to change 123456 to whatever password you want):

Bash

sudo podman exec -it pihole pihole setpassword '123456'

3. Run the router automation script:

Finally, let's tell the router to use your new setup. Run this exact block of code:

Bash

HOST_IP=$(ip -4 route get 1.1.1.1 | awk '{print $7; exit}')

python3 tenda_dns_updater.py \
    --router-ip "192.168.0.1" \
    --password "admin" \
    --pihole-ip "${HOST_IP}"

Important Note: If you previously changed your Tenda router's admin password to something else, make sure you replace "admin" in the command above with your real router password!

Part 5: The "Gotcha" — Fixing Device Settings

Here is where a lot of beginners trip up. You’ve set everything up perfectly, but ads are still loading on your phone. Why?

Modern phones and web browsers have a feature called "Private DNS" or "Secure DNS" (DoH). This feature encrypts your web traffic and sends it straight to Google or Cloudflare—completely bypassing your router and your new Pi-hole.

To force your devices to use your ad blocker, you must turn this feature off.

  • Android Phones: Go to Settings -> Search for Private DNS -> Set it to Off.

  • iPhones / iPads: Go to Settings -> Tap your Apple ID name at the top -> iCloud -> Private Relay -> Turn it Off.

  • Chrome / Edge Browsers: Go to Settings -> Privacy and Security -> Security -> Find Use secure DNS and toggle it Off.

Part 6: How to Block Any Domain (e.g., TikTok) Network-Wide

Pi-hole blocks standard ads out of the box. But the real power is that you can completely ban specific apps or websites from your entire house.

Let's say you want to block TikTok.

Method A: The Easy Visual Way

  1. Open your web browser and go to the address the first script gave you (usually something like [http://192.168.0.109/admin](http://192.168.0.109/admin)).

  2. Log in with the password you set (123456).

  3. Click Domains on the left menu.

  4. Type in tiktok.com.

  5. Check the box that says Add domain as wildcard (this ensures it blocks [www.tiktok.com](https://www.tiktok.com), video.tiktok.com, etc., not just the main page).

  6. Click Add to Blocklist.

Method B: The Hacker Way (Terminal)

Apps like TikTok are sneaky and load videos from secondary servers. To completely nuke it in one go, just paste this into your terminal:

Bash

sudo podman exec -it pihole pihole deny --wild tiktok.com tiktokcdn.com byteoversea.com ibyteimg.com musical.ly ttwstatic.com

Final Verification Checklist

You're done! Let's make sure it's working:

  1. Check the Dashboard: Open your browser to [http://192.168.0.109/admin](http://192.168.0.109/admin) (or whatever IP the script gave you). It should load a beautiful dashboard showing an "Active" green status.

  2. Watch the Matrix: Click Query Log in the left menu of the dashboard. Pick up your phone and open a website. You will literally see your phone's requests popping up on your computer screen in real-time.

  3. The Ultimate Test: Go visit a messy, ad-heavy news website on your phone or laptop. Enjoy the clean, lightning-fast, ad-free experience!

On this page

The Master Guide: Build a Network-Wide Ad Blocker from ScratchThe Game PlanPart 1: Install the Required ToolsPart 2: Create the Setup Script (deploy_pihole.sh)Part 3: Create the Router Automation Script (tenda_dns_updater.py)Part 4: Let's Fire It All Up!Part 5: The "Gotcha" — Fixing Device SettingsPart 6: How to Block Any Domain (e.g., TikTok) Network-WideFinal Verification Checklist
0% read
All articlesFiled under Cyber Security