cmd / hostctl

I manage /etc/hosts for local development and DNS-level ad blocking with a CLI tool:

hostctl

Local apps

Browsers treat http://localhost and http://*.localhost as potentially trustworthy origins, providing Secure Context features without TLS.

Running multiple apps on different subdomains and ports (e.g., blog.localhost:2000, htmz.localhost:2002) lets me test cross-origin security without TLS:

Ad blocking

Unlike browser extension ad blockers, DNS-level blocking works on all apps on my device (not only web browsers).

Unlike DNS sinkholes like Pi-hole, it only works on my laptop (not phones or tablets on the network) but it does not require an additional always-on device such as a Raspberry Pi and it works reliably when using the laptop away from home.

Ad/tracker blocking is enabled by default:

hostctl

To disable blocking while keeping local app entries intact:

hostctl --unblock

Script:

#!/bin/bash
#
# https://github.com/croaky/laptop/blob/main/bin/hostctl

set -euo pipefail

custom_hosts_entries() {
  cat <<EOF
# macOS defaults
255.255.255.255 broadcasthost

# local apps
127.0.0.1 blog.localhost     # :2000
127.0.0.1 bsfeeds.localhost  # :2001
127.0.0.1 eds.localhost      # :3000
127.0.0.1 htmz.localhost     # :2002
127.0.0.1 neogit.localhost   # :2003
EOF
}

if [[ "${1:-}" == "--unblock" ]]; then
  cat <<EOF | sudo tee /etc/hosts >/dev/null
# IPv4
127.0.0.1 localhost

# IPv6
::1 localhost

$(custom_hosts_entries)
EOF
else
  # Block ads, trackers, and malicious websites at the DNS host level.
  curl -s https://winhelp2002.mvps.org/hosts.txt | tr -d '\r' | sudo tee /etc/hosts >/dev/null

  # Append custom entries
  (echo && custom_hosts_entries) | sudo tee -a /etc/hosts >/dev/null
fi

# Flush DNS cache
sudo killall -HUP mDNSResponder

I use the 2000 port range for servers written in Go and the 3000 port range for servers written in Ruby.

← All articles