Confused by complex code? Let our AI-powered Code Explainer demystify it for you. Try it out!
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.
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:
/etc/hostsC:\Windows\System32\drivers\etc\hostsThis 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.
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.
A naive approach would be to just append lines to the end of the hosts file. But that creates problems:
block twice duplicates every entry.unblock has no way to know which lines are ours.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 <<<
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:
if START_MARKER in content check means rerunning block won't duplicate entries — it replaces the old block cleanly.\t between IP and hostname follows the hosts file convention and keeps things readable.len(SITES_TO_BLOCK) // 2 for the count because each domain has both a www and non-www entry.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.
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]}")
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)
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
...
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.
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.
Create two scheduled tasks that run with highest privileges:
python (or full path like C:\Python311\python.exe)C:\Users\You\website_blocker.py blockRepeat for the unblock task at 6 PM with argument unblock instead.
This tool is built to be extended. Here are a few directions:
SITES_TO_BLOCK to an external config.json so you can edit the list without touching the script.ipconfig /flushdns after modifying the hosts file so changes take effect immediately without a restart.You now have a clean, cross-platform website blocker that:
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! ♥
Just finished the article? Now, boost your next project with our Python Code Generator. Discover a faster, smarter way to code.
View Full Code Create Code for Me
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!