6.9 KiB
Administrators Guide
All scripts below live in the routlin project root and must be run as root (or with sudo) unless noted otherwise.
install.py
Setup wizard. Installs system packages, configures Docker, sets up the dashboard container, and installs all systemd timers.
sudo python3 install.py
sudo python3 install.py --yes # (or -y) accept all prompts automatically
Safe to re-run. Will not duplicate files. After install.py completes, run core.py --apply to push config.json into the live system for the first time.
core.py
The main configuration engine. Reads config.json and applies it to systemd-networkd, per-VLAN dnsmasq instances, nftables, WireGuard, FreeRADIUS, and Avahi. Most dashboard Save, Apply, and Fix operations ultimately trigger core.py via the queue timer.
sudo python3 core.py --apply # apply full config (safe to re-run multiple times)
sudo python3 core.py --apply --dry-run # preview changes without making them
sudo python3 core.py --disable # interactive wizard to revert the router to a plain client
sudo python3 core.py --disable --dry-run # preview what --disable would remove
sudo python3 core.py --merge-blocklists # merge downloaded blocklists and reload dnsmasq
sudo python3 core.py --view-configs # print active per-VLAN dnsmasq config files
sudo python3 core.py --view-leases # print active DHCP leases
sudo python3 core.py --view-rules # print active nftables ruleset
sudo python3 core.py --reset-leases # reset all DHCP leases
sudo python3 core.py --reset-leases 30 # reset leases for VLAN 30 only
sudo python3 core.py --status # show service and timer status
Dashboard equivalents:
| Flag | Dashboard |
|---|---|
| --apply | Actions page - Apply Now button |
| --merge-blocklists | DNS Blocking page - Download Blocklists button |
| --view-leases | DHCP Reservations page (active leases section) |
maintenance.py
Runs on a timer (default every 10 minutes). Runs ddns.py --update, rotates FreeRADIUS logs, refreshes the ARP cache, and runs metrics.py --collect. Run manually to trigger all tasks immediately without waiting for the timer.
sudo python3 maintenance.py
Timer: routlin-maintenance.timer - interval set in config.json under ddns.general.timer_interval (default 10 minutes).
metrics.py
Collects DNS statistics from running dnsmasq instances and stores them in the metrics database. Also collects and prunes per-query DNS logs. Run --collect manually to update metrics immediately rather than waiting for the maintenance timer. Run --view to print an all-time summary to the terminal. The dashboard is able to display updated information on the DNS Metrics page after --collect runs.
sudo python3 metrics.py --collect # collect and store metrics now
sudo python3 metrics.py --view # display all-time metrics summary
maintenance.py calls metrics.py --collect automatically on each tick.
health.py
Runs health checks across all services, configuration files, nftables rules, VLAN interfaces, DHCP pools, disk space, upstream DNS, and FreeRADIUS logs. Writes results to .health.
sudo python3 health.py --collect # run checks and write .health (used by timer)
sudo python3 health.py --view # run checks, write .health, and print results
--view gives an immediate health report without waiting for the timer. The dashboard health banner reads the same .health file, so running either flag manually refreshes what the dashboard shows on next page load.
Timer: routlin-health-check.timer - every 5 minutes.
ddns.py
Updates DDNS provider(s) with the current public IP. Called directly by do_dashboard_queue.sh for on-demand triggers from the dashboard, and by maintenance.py on each timer tick. Shares cache files (.ddns-last-ip-*, .ddns-last-service) and ddns.log across both callers. The DDNS page shows provider status and last update time.
sudo python3 ddns.py --update # run one update, advancing the check IP service rotation
sudo python3 ddns.py --update --force # update unconditionally, ignoring cached IP
sudo python3 ddns.py --getip # print current public IP and exit, advancing the check IP service rotation
dl_blocklists.py
Downloads remote DNS blocklists defined in config.json to the blocklists/ directory. Does not reload dnsmasq on its own - follow with core.py --merge-blocklists to merge and reload.
sudo python3 dl_blocklists.py
sudo python3 core.py --merge-blocklists
Timer: routlin-dns-blocklist-update.timer - daily at the time configured in config.json (default 02:30 local time). The timer runs both steps automatically.
Dashboard equivalent: DNS Blocking page - Download Blocklists button (runs both steps).
create_vpn_peer.py
Generates a WireGuard keypair, adds the peer to config.json, and writes a ready-to-import client .conf file. Follow with core.py --apply to make the peer(s) that you generate live.
sudo python3 create_vpn_peer.py --name laptop --ip 192.168.40.2 --vlan-id 40
sudo python3 create_vpn_peer.py --name phone --ip 192.168.40.3 --vlan-id 40 --split-tunnel
sudo python3 create_vpn_peer.py --name laptop --ip 192.168.40.2 --iface wg0
sudo python3 core.py --apply
| Flag | Description |
|---|---|
| --name NAME | Peer name (required) |
| --ip IP | Peer IP within the VPN subnet (required) |
| --vlan-id ID | Target VPN VLAN ID (use this or --iface) |
| --iface IFACE | WireGuard interface name e.g. wg0 (use this or --vlan-id) |
| --split-tunnel | Route only VPN subnet traffic through the tunnel (default is full tunnel) |
| --output PATH | Output path for the client .conf file |
Transfer the generated .conf file to the client device securely (scp, QR code, etc.). Never send it over unencrypted channels.
Dashboard equivalent: VPN page - Add Peer form.
check_captive_users.py
Expires captive portal sessions that have exceeded their time limit or account expiry, and writes the corresponding nftables disallow commands to the captive queue. The Captive Portal page shows active sessions. Expiry is handled automatically by the timer; there is no manual trigger in the dashboard.
sudo python3 check_captive_users.py
Timer: routlin-captive-check.timer - every 5 minutes.
Timer Reference
| Timer | Script | Interval |
|---|---|---|
routlin-dashboard-queue.timer |
dashboard queue processor | 30 seconds |
routlin-captive-queue.timer |
captive portal queue | 10 seconds |
routlin-captive-check.timer |
check_captive_users.py | 5 minutes |
routlin-health-check.timer |
health.py --collect | 5 minutes |
routlin-maintenance.timer |
maintenance.py | 10 minutes (configurable) |
routlin-dns-blocklist-update.timer |
dl_blocklists.py + core.py --merge-blocklists | Daily at configured time |