• HTML 43.6%
  • Python 40.9%
  • Shell 15.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
earthonion cd9a773ac8
router-detox: cap tick at 30s + re-arm timer on restart
Observed 2026-06-06: one router-detox.service invocation wedged for
~58 minutes (probably a tc/curl hang), and because the .timer chains
via OnUnitActiveSec=60s — which is relative to the *finish* of the
previous run — the timer's NextElapseUSecMonotonic went to infinity
and the throttle silently stopped applying for six days. Two fixes:

  router-detox.service:
    TimeoutStartSec=30
      Hung ticks now get SIGTERM'd after 30s instead of stalling the
      chain indefinitely.

  router-detox.timer:
    OnActiveSec=30s
      OnBootSec=30s only triggers the chain on a fresh boot.
      OnActiveSec=30s re-seeds the chain whenever the timer is
      restarted without a reboot (e.g. after a daemon-reload), so
      'systemctl restart router-detox.timer' is enough to bring it
      back. OnUnitActiveSec=60s alone can only *sustain* the chain;
      it can't bootstrap it.
2026-06-12 07:41:36 -04:00
portal router-detox: cap tick at 30s + re-arm timer on restart 2026-06-12 07:41:36 -04:00
README.md Drop social-media blocklist; keep just the detox throttle 2026-06-03 21:32:47 -04:00
Setup.sh Drop social-media blocklist; keep just the detox throttle 2026-06-03 21:32:47 -04:00

digital-detox-router

Turns a fresh Debian install into a LAN router that

  • Hands out DHCP + NATs LAN → WAN (iptables + isc-dhcp-server)
  • Ships an HTTP management portal at http://<gateway>/ with
    • Live throughput + vnstat totals
    • DHCP leases (with hostname/MAC/expiry)
    • Per-LAN-IP conntrack session counts
    • Digital-detox throttle: turn the LAN download speed down to n kbps during a configurable window so phones stay connected but unusable
    • Kick / unkick any MAC
  • And a full Cockpit system panel at https://<gateway>:9090/

Both UIs bind LAN-only; the public WAN side drops :80 + :9090 at iptables.

Install

git clone https://git.etawen.dev/earthonion/digital-detox-router.git
cd digital-detox-router
# Edit the interface names at the top of Setup.sh first:
#   WAN_INTERFACE="eno1"
#   LAN_INTERFACE="enp8s0"
sudo bash Setup.sh

The portal is installed by default. Skip it with INSTALL_PORTAL=0 sudo bash Setup.sh if you only want the base router.

On first install, a random 16-char admin password is generated and printed once. Save it — it is not stored in cleartext on the box (bcrypt-hashed into /etc/router-dashboard/config.ini).

Layout

/opt/router-dashboard/          Flask app (app.py + templates/)
/etc/router-dashboard/          config.ini, detox.json, kicked.txt
/usr/local/sbin/                router-dashboard-helper, router-detox
/etc/systemd/system/            router-dashboard.service, router-detox.{service,timer}

What persists across reboot

Everything. iptables-save → /etc/iptables/rules.v4 (restored by netfilter-persistent), net.ipv4.ip_forward=1 in /etc/sysctl.conf, every systemd unit is enabled, the NetworkManager profile for the LAN side has autoconnect=yes. dhcpd has a Restart=on-failure drop-in for interface flaps.

Notes

  • dhcpd does NOT accept CIDR shorthand in subnet stanzas — write subnet 192.168.1.0 netmask 255.255.255.0, not subnet 192.168.1.0/24 netmask ....
  • The detox throttle is tc qdisc tbf on LAN egress only, so the router's own outbound (CI jobs, container pulls) is not penalised.
  • Minimum throttle rate is capped at 16 kbps — lower than that and DHCP renewals start timing out.