How to Build a Website Blocker in Python

Learn how to build a cross-platform website blocker in Python that modifies the hosts file to block distracting sites. Includes scheduling with cron and Task Scheduler. Pure standard library — no pip install needed.
  · 8 min read · Updated jun 2026 · Ethical Hacking · General Python Tutorials

Get a head start on your coding projects with our Python Code Generator. Perfect for those times when you need a quick solution. Don't wait, try it today!

We all know the drill: you sit down to code, and twenty minutes later you're three levels deep in a Reddit thread about something you didn't even care about. Browser extensions exist, but they're easy to disable in a moment of weakness. What if you could block distracting websites at the operating system level — and automate it so the block kicks in during work hours and lifts when you clock out?

In this tutorial, we'll build a website blocker in Python that modifies your system's hosts file to redirect distracting sites to 127.0.0.1 (localhost). It works on Windows, macOS, and Linux, uses zero third-party libraries (pure Python standard library), and comes with block, unblock, and status commands. We'll also set up automated scheduling so it runs on its own — like a productivity firewall you set once and forget.

How the Hosts File Works

Before your computer asks a DNS server "hey, where is facebook.com?", it checks a local file called hosts. This file maps domain names to IP addresses and takes priority over any external DNS lookup. If you add this line:

127.0.0.1    facebook.com

...then every request to facebook.com resolves to your own machine, where nothing serves the page. The browser spins for a moment and gives up. No sketchy extension, no dependency on willpower — just a one-line redirect at the OS level.

The hosts file lives at:

  • Linux / macOS: /etc/hosts
  • Windows: C:\Windows\System32\drivers\etc\hosts

No Dependencies Needed

This entire project uses only Python's standard library — sys, platform, and pathlib are all built-in. No pip install required.

Create a file named website_blocker.py and let's build it step by step.

Step 1: Configuration & Cross-Platform Hosts Path

Start with the imports, the list of sites to block, and a helper that picks the correct hosts path for the current OS:

import sys
import platform

# ------------------------------------------------------------
# CONFIGURATION — edit this list to block different sites
# ------------------------------------------------------------

SITES_TO_BLOCK = [
    # Social media
    "www.facebook.com", "facebook.com",
    "www.twitter.com",   "twitter.com",
    "www.instagram.com", "instagram.com",
    "www.reddit.com",    "reddit.com",
    # Video / entertainment
    "www.youtube.com",   "youtube.com",
    "www.tiktok.com",    "tiktok.com",
    "www.twitch.tv",     "twitch.tv",
]

REDIRECT_IP = "127.0.0.1"

# Markers keep our entries isolated so we never touch
# other entries in the hosts file.
START_MARKER = "# >>> WEBSITE BLOCKER START >>>"
END_MARKER   = "# <<< WEBSITE BLOCKER END <<<"

# ------------------------------------------------------------
# Cross‑platform hosts path
# ------------------------------------------------------------

def get_hosts_path():
    """Return the absolute path to the hosts file for this OS."""
    system = platform.system()
    if system == "Windows":
        return r"C:\Windows\System32\drivers\etc\hosts"
    # macOS and Linux both use /etc/hosts
    return "/etc/hosts"

HOSTS_PATH = get_hosts_path()

Each site gets two entries — one with www. and one without — because facebook.com and www.facebook.com are technically different hostnames and both need to be redirected.

The START_MARKER and END_MARKER are comment lines delimiters. They let us add and remove our entries without touching anything else in the hosts file — critical for safety.

Step 2: Why Markers Matter

A naive approach would be to just append lines to the end of the hosts file. But that creates problems:

  • Running block twice duplicates every entry.
  • Running unblock has no way to know which lines are ours.
  • You might accidentally delete legitimate entries added by other software.

By wrapping our entries between two comment markers, we have a clean "section" we can add, remove, or replace without ambiguity. After running the script, the bottom of your hosts file will look like this:

# >>> WEBSITE BLOCKER START >>>
127.0.0.1    www.facebook.com
127.0.0.1    facebook.com
127.0.0.1    www.twitter.com
127.0.0.1    twitter.com
127.0.0.1    www.instagram.com
127.0.0.1    instagram.com
127.0.0.1    www.reddit.com
127.0.0.1    reddit.com
127.0.0.1    www.youtube.com
127.0.0.1    youtube.com
127.0.0.1    www.tiktok.com
127.0.0.1    tiktok.com
127.0.0.1    www.twitch.tv
127.0.0.1    twitch.tv
# <<< WEBSITE BLOCKER END <<<

Step 3: Blocking Websites

The block_websites() function reads the current hosts file, strips out any previous blocker section (so rerunning is safe), builds a fresh block with the current site list, and writes everything back:

def block_websites():
    """Write (or refresh) the blocker block into the hosts file."""
    # Read the current file
    with open(HOSTS_PATH, "r") as fh:
        content = fh.read()

    # Strip any previous block so we start fresh
    if START_MARKER in content:
        content = content.split(START_MARKER)[0].rstrip("\n") + "\n"

    # Build the block
    block_lines = [START_MARKER + "\n"]
    for site in SITES_TO_BLOCK:
        block_lines.append(f"{REDIRECT_IP}\t{site}\n")
    block_lines.append(END_MARKER + "\n")

    # Write everything back
    with open(HOSTS_PATH, "w") as fh:
        fh.write(content)
        fh.writelines(block_lines)

    unique_sites = len(SITES_TO_BLOCK) // 2
    print(f"[+] Blocked {unique_sites} websites "
          f"({len(SITES_TO_BLOCK)} URLs) → {REDIRECT_IP}")

Key details:

  • The if START_MARKER in content check means rerunning block won't duplicate entries — it replaces the old block cleanly.
  • The tab \t between IP and hostname follows the hosts file convention and keeps things readable.
  • We use len(SITES_TO_BLOCK) // 2 for the count because each domain has both a www and non-www entry.

Step 4: Unblocking Websites

Unblocking is even simpler — just cut out everything between (and including) our two markers:

def unblock_websites():
    """Remove the blocker block from the hosts file."""
    with open(HOSTS_PATH, "r") as fh:
        content = fh.read()

    if START_MARKER not in content:
        print("[*] No websites are currently blocked.")
        return

    # Cut out the marked section
    before = content.split(START_MARKER)[0].rstrip("\n")
    after  = content.split(END_MARKER)[-1]
    new_content = before + "\n" + after.lstrip("\n")

    with open(HOSTS_PATH, "w") as fh:
        fh.write(new_content)

    print("[+] All websites unblocked. Focus mode off.")

The rstrip("\n") and lstrip("\n") calls prevent leftover blank lines from accumulating after repeated block/unblock cycles.

Step 5: Checking Status

A quick status check shows you which sites are currently blocked and how many URLs are redirected:

def show_status():
    """Print which websites are currently blocked."""
    with open(HOSTS_PATH, "r") as fh:
        content = fh.read()

    if START_MARKER not in content:
        print("[*] No websites are currently blocked.")
        return

    block = content.split(START_MARKER)[1].split(END_MARKER)[0]
    sites = [line.strip() for line in block.split("\n")
             if line.strip() and not line.strip().startswith("#")]

    print(f"[*] {len(sites)} URLs currently blocked → {REDIRECT_IP}:")
    for site in sites:
        print(f"    {site.split()[-1]}")

Step 6: The CLI Interface

Finally, wire everything to a simple command-line interface that dispatches on the first argument:

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Website Blocker — block distracting sites via /etc/hosts\n")
        print("Usage:")
        print("  sudo python website_blocker.py block")
        print("  sudo python website_blocker.py unblock")
        print("  python website_blocker.py status")
        sys.exit(1)

    command = sys.argv[1].lower()

    if command == "block":
        block_websites()
    elif command == "unblock":
        unblock_websites()
    elif command == "status":
        show_status()
    else:
        print(f"[!] Unknown command: {command}")
        print("Valid commands: block, unblock, status")
        sys.exit(1)

Step 7: Running with Admin Privileges

The hosts file is protected by the OS — editing it requires elevated privileges. Here's how to run the script on each platform:

Linux & macOS:

$ sudo python website_blocker.py block
[+] Blocked 7 websites (14 URLs) → 127.0.0.1

$ python website_blocker.py status
[*] 14 URLs currently blocked → 127.0.0.1:
    www.facebook.com
    facebook.com
    ...

$ sudo python website_blocker.py unblock
[+] All websites unblocked. Focus mode off.

Windows:

Open Command Prompt or PowerShell as Administrator (right-click → Run as Administrator), then:

C:\> python website_blocker.py block
[+] Blocked 7 websites (14 URLs) → 127.0.0.1

The status command reads the file without writing, so it works without admin:

C:\> python website_blocker.py status
[*] 14 URLs currently blocked → 127.0.0.1:
    www.facebook.com
    facebook.com
    ...

Step 8: Scheduling Automatic Blocking

The real power move is automation. Schedule the blocker to run at 9 AM (block distractions) and 6 PM (unblock) so it works on autopilot.

Linux / macOS — cron

Edit your crontab:

$ sudo crontab -e

Add these two lines (adjust the path to your script):

# Block at 9:00 AM every weekday
0 9 * * 1-5 /usr/bin/python3 /home/you/website_blocker.py block

# Unblock at 6:00 PM every weekday
0 18 * * 1-5 /usr/bin/python3 /home/you/website_blocker.py unblock

Since crontab runs as root (via sudo crontab -e), no password prompt is needed — the script edits the hosts file silently in the background.

Windows — Task Scheduler

Create two scheduled tasks that run with highest privileges:

  1. Open Task SchedulerCreate Basic Task
  2. Name: "Block Distracting Sites"
  3. Trigger: Daily at 9:00 AM, weekdays only
  4. Action: Start a program
  5. Program: python (or full path like C:\Python311\python.exe)
  6. Arguments: C:\Users\You\website_blocker.py block
  7. Check "Run with highest privileges"

Repeat for the unblock task at 6 PM with argument unblock instead.

Extension Ideas

This tool is built to be extended. Here are a few directions:

  • JSON config file: Move SITES_TO_BLOCK to an external config.json so you can edit the list without touching the script.
  • Time-aware blocking: Have the script check the current time and block/unblock accordingly in a single invocation — useful for running from a cron job that fires every minute.
  • GUI frontend: Wrap it in a Tkinter or PyQt window with checkboxes for each site and a big ON/OFF toggle.
  • Pomodoro integration: Block during 25-minute focus sessions, unblock during 5-minute breaks.
  • Flush DNS cache: On Windows, run ipconfig /flushdns after modifying the hosts file so changes take effect immediately without a restart.

Conclusion

You now have a clean, cross-platform website blocker that:

  • Uses zero dependencies — pure Python standard library
  • Safely manages the hosts file with marker-delimited sections
  • Works on Windows, macOS, and Linux
  • Can be scheduled with cron or Task Scheduler for set-and-forget productivity

The full code is under 100 lines and every function does one thing well. Drop it on your machine, schedule it, and enjoy the extra focus.

Happy (productive) coding! ♥

Ready for more? Dive deeper into coding with our AI-powered Code Explainer. Don't miss it!

View Full Code Explain My Code
Sharing is caring!




Comment panel

    Got a coding query or need some guidance before you comment? Check out this Python Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!