The web portal for the tables that run the plant.
docsis_server keeps every piece of its state in MySQL, so anything that can write a row can run the plant. docsis_admin is that interface: one small Go binary, serving html/template with htmx, that connects to the MySQL servers of several plants at once and switches between them from a selector in the header. It needs nothing from the server but a MySQL account.
Repository: github.com/mmqr-developer/docsis_admin · The four DOCSIS projects also have a site of their own at docsis-admin.com.
Admins edit, Help Desk looks up
Admins edit the tables — modem inventory, IPv4 and IPv6 address pools, DHCP option groups, configuration fragments, leases and the blacklist — and an edit saves when you leave the cell. Help Desk searches a CM MAC, CM IP, CPE MAC or CPE IP across every configured plant at once, then opens the modem: what it was entitled to, where it is now, the equipment behind it, and its DHCP and TFTP logs.
dhcp_leases and dhcp6_leases, with lease pinningdocsis_modemconfig_nets and cmts_networks6config_opts, config_opts_macs, dhcp_options6config_modemdhcp_bad_macsEvery screen is open to every signed-in operator except Operators, which lists every account on the console with its role and its last sign-in — a map of who to attack, and no help to somebody on the phone about a modem. It is refused at the route, not only hidden in the nav.
Three roles, and the middle line matters
The superuser creates admins and help-desk accounts. An admin creates help-desk accounts only. Help Desk creates nobody.
An admin cannot make an admin
So admin access cannot be used to widen itself. Changing an existing account needs the same right as creating one — otherwise an admin could take over an admin account that already exists instead of making a new one. Every rule is enforced on the write path: a Help Desk account posting directly to an admin endpoint gets a 403.
The superuser has no row
It is defined in the config file and nowhere in the database, so write access to the accounts table cannot mint one, and revoking it is an edit to a root-owned file plus a restart rather than an UPDATE. It exists to bootstrap a fresh install and to get back in when the account database is unreachable — not for daily use. The Operators page never prints its login name.
Sessions end at four in the morning
Not after a fixed number of hours, which logs people out mid-task at a time that is different for everyone. Help Desk runs to the coming Sunday at 04:00, an admin to the coming 04:00, and an admin who presented a code to the 04:00 two days after that — where the operator is, from the zone the browser reports. A cutover under two hours away is skipped for the next one.
What guards the door
<input type="password">, and an admin resetting six people in a morning would be asked six times to save a credential that is not theirs. Your own password is still a real password field, because a browser remembering that is remembering the right thing.
trusted_proxies, and the chain is walked right to left, so a forged entry cannot choose which cooldown bucket it lands in.
GET /diagnostics reports the build, the route table, every configured plant and whether it is answering. Admin-only, and it never contains a secret.
One database, one binary, one file
You need Go, MySQL 8.x or MariaDB 10.11 or newer for the console's own small database, network reach to each plant's MySQL server, and nginx or similar in front.
# 1. the console's own database — accounts and an audit trail, nothing else mysql -u root -p -e "CREATE DATABASE docsis_admin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" mysql -u root -p docsis_admin < scripts/schema-docsis-admin.sql # no DELETE in the grant: accounts are disabled, never removed, so the audit trail keeps pointing somewhere mysql -u root -p -e "CREATE USER 'docsis_admin'@'%' IDENTIFIED BY '...'; GRANT SELECT, INSERT, UPDATE ON docsis_admin.* TO 'docsis_admin'@'%'" # 2. build 3. the superuser password ./build.sh ./docsis_admin_p7775 -hashpw # 4. configure cp docsis-admin.example.json ~/config/docsis-admin.json chmod 600 ~/config/docsis-admin.json # 5. run ./docsis_admin_p7775 -nofork # foreground, for a first look ./docsis_admin_p7775 # daemonised
Sign in as the superuser, create your admins, and stop using the superuser. The config file carries a MySQL password for every plant the console can reach, which makes it a credential for the plants themselves: keep it outside the repository, mode 0600, and give each plant account only the rights it needs — read_only: true on a plant this console should never write.
# nginx: the console lives under /app/, with three routes beside it
location /app/ { proxy_pass http://127.0.0.1:7775; }
location /login { proxy_pass http://127.0.0.1:7775; }
location /logout { proxy_pass http://127.0.0.1:7775; }
location /static/ { proxy_pass http://127.0.0.1:7775; }
Stated rather than left to be discovered
docsis encoder uses, and shipping a second copy of that table would mean two that drift. Those endpoints answer 501; the Raw text view is how a fragment is edited today.
/diagnostics uses it; it is not on the page yet because a database round trip per navigation is a lot for a decoration.