Unifi Custom DNS Blocklist Manager: Project Summary and Web Application Template
Overview
This project is inspired by a Bash script designed for Unifi network environments (or similar router/DNS setups) to manage a custom DNS blocklist for ad-blocking, malware prevention, phishing protection, and crypto-mining domain blocking. The original script monitors the CoreDNS process (a lightweight DNS server often used in containerized or edge router setups) for PID changes, indicating a restart or external modification. Upon detection, it automatically updates or merges a domain blocklist file (/run/utm/domain_list/domainlist_0.list) by fetching and processing lists from configurable URLs, applying removal rules from a whitelist file (/run/utm/domain_list/domainlist_1.list), cleaning invalid entries, and ensuring the active blocklist remains effective. It includes time-based throttling (e.g., full updates only every 3 days unless forced) to avoid excessive network fetches, while still handling external changes to the blocklist (e.g., from other system software) by merging them with the last known custom list (/sdcard1/combined-blocklist.txt). If the process isn't running, it resets monitoring. All actions are logged with timestamps for debugging.
The script's core functionality—automated blocklist updating, merging, validation, and DNS restarts—serves as the foundation for a modern web application. This app transforms the script into a user-friendly, secure web tool with a backend for automation and a frontend for interactive management. It maintains the script's logic for PID monitoring and auto-reapplication but adds a dark-themed web interface using Tailwind CSS for accessibility and aesthetics. The backend (preferably implemented in Go for efficiency and cross-platform compatibility) handles file operations, process management, and security, while the frontend provides intuitive controls. This setup is ideal for home lab enthusiasts, small network admins, or Unifi users seeking a Pi-hole or AdGuard Home-like experience with custom Unifi integration.
The app emphasizes security: all inputs are validated and sanitized to prevent code injection (e.g., via SQL injection if using a database, or command injection in shell calls). It supports a single administrative user with multi-factor authentication (MFA, e.g., TOTP via apps like Google Authenticator), configurable at runtime via command-line flags. Without authentication, no backend interactions are allowed—users are redirected to a login page. Configuration is stored in a JSON or YAML file (config.json or similar) in the executable's directory; if absent, the app generates a default config with placeholders for user credentials, paths, and settings.
Key Features and Architecture
The web app replicates and extends the script's behavior, dividing responsibilities between backend and frontend while preserving modularity (e.g., via functions/services for update checks, merging, and restarts). It runs as a standalone executable (e.g., ./unifi-blocklist-manager -port=8080), potentially as a service on a Unifi gateway or separate server.
Backend (Go-Recommended Implementation)
- PID Monitoring Loop: Mirrors the script's infinite loop, checking CoreDNS PID every 5 seconds (configurable). If a change is detected without a user-initiated "Apply" action (tracked via an in-memory flag or timestamp), it triggers the blocklist update/merge logic automatically. Logs all actions to stdout or a file for auditing.
- Blocklist Update Logic:
- Full Update: If forced or 3+ days since last update (tracked via
/sdcard1/last_update.txt), fetch domains from URLs in/sdcard1/urllist.txt(or a database equivalent for scalability). Merge with existing blocklist, clean invalid domains (e.g., using regex filters like the script'sgreppatterns), apply removals from/run/utm/domain_list/domainlist_1.list(via AWK-like logic in Go), and save to the active blocklist file. Update timestamp and restart CoreDNS (pkill coredns). - Partial/Merge Update: If time threshold not met, compare active blocklist with last custom list (
/sdcard1/combined-blocklist.txt). If different (e.g., due to external modifications), merge uniquely (sort and dedupe), save, and restart CoreDNS. - Default URLs are pre-populated if the URL list file is missing, pulling from ad-blocking sources like AdGuard filters, Firebog, and Phishing Army.
- Full Update: If forced or 3+ days since last update (tracked via
- Process Management: Securely execute system commands (e.g.,
pgrep,pkill) with input sanitization. Handle non-running CoreDNS by resetting PID file. - Authentication and Config:
- Single user account: Configured via flags like
./app -setup-user=username -setup-pass=password -setup-mfa-secret=base32secret. MFA uses TOTP; on first run, generate and display a QR code for scanning. - Config file: Auto-created if missing, containing encrypted credentials, file paths (e.g., blocklist locations), update delay (default 3 days), and check interval (default 5 seconds). Use Go libraries like Viper for config management.
- Session-based auth: JWT or cookie sessions with short expiration; MFA required on login. Unauthenticated requests to management endpoints return 401/redirect.
- Single user account: Configured via flags like
- API Endpoints (RESTful, e.g., using Gin framework):
- GET
/api/urllists: List current URLs (with status: enabled/disabled). - POST
/api/urllists/add: Add new URL (validate as valid HTTP(S) URL). - DELETE
/api/urllists/remove: Remove URL. - PATCH
/api/urllists/toggle: Enable/disable URL. - GET
/api/domains/search?query=example*: Search blocklist with wildcard support (e.g., using regex like.*example.*for*example*). - POST
/api/domains/add: Add domain (validate as valid FQDN). - DELETE
/api/domains/remove: Remove domain. - POST
/api/apply: Trigger full/partial update and CoreDNS restart (sets a flag to indicate user-initiated change). - All endpoints require auth headers; validate inputs (e.g., no shell metachars, length limits).
- GET
- Security Measures: Use prepared statements if database involved; escape all shell args; rate-limit API calls; HTTPS enforcement.
Frontend (Dark Theme with Tailwind CSS)
- Dashboard Layout: A clean, responsive single-page app (SPA) or server-rendered pages (e.g., using Go templates or a framework like Echo with HTMX for interactivity). Dark theme by default (e.g., Tailwind's dark mode with slate/gray palettes, accents in blue for buttons).
- URL List Management:
- Table view of URLs from
/sdcard1/urllist.txt(fetched via API), showing URL, description (auto-fetched or manual), enabled status, and actions (add, remove, toggle). - Add form: Input for new URL, with validation (client-side regex for URL format).
- Similar to AdGuard Home's "Filters" tab or Pi-hole's "Adlists" under Group Management.
- Table view of URLs from
- Domain Search and Management:
- Search bar for final blocklist domains, supporting wildcards (e.g.,
*google*searches regex-matched entries). Results in a paginated table with domain, source (if trackable), and remove button. - Add domain form: Simple input for FQDN, append to blocklist or a custom additions file.
- Inspired by Pi-hole's query log/search or AdGuard Home's domain filters.
- Search bar for final blocklist domains, supporting wildcards (e.g.,
- Apply Changes: Prominent button that calls
/api/apply, showing progress spinner and confirmation (e.g., "Changes applied, CoreDNS restarted"). Warns about potential network disruption. - Login Page: Form for username/password + MFA code. Responsive, with error messages for invalid creds.
- Additional Views:
- Logs page: Real-time or polled view of script-like logs (e.g., PID changes, updates).
- Settings: View/edit config (e.g., update delay), but sensitive fields read-only.
- UI Best Practices: Mobile-friendly (Tailwind responsive classes), accessible (ARIA labels), and minimalistic. No JavaScript-heavy if possible; use forms and HTMX for AJAX-like updates to keep it lightweight.
Usage and Deployment
- Run:
./unifi-blocklist-manager [-port=8080] [-force] [-setup-user=...]. The-forceflag enables full updates on every trigger, overriding time checks. - Deployment: As a systemd service on Linux (e.g., Unifi OS). Expose on local network; use reverse proxy (e.g., Nginx) for HTTPS.
- Similar Tools: Draws from Pi-hole (adlist management, group blocking) and AdGuard Home (filter lists, domain search) for UI inspiration, but tailored for Unifi/CoreDNS integration.
Extra notes:
- create Dark theme Tailwind CSS front end, what works good on desktop pc as on small mobile device screen
- use html template, so the layout is preserved across all pages ( similar what Python Jinja templates do - i define base.html and then i referense it in index.html and extend it with page content...)
- The user input should be secure and interaction with website and if someone would attempt to use some non-interactive access via bot or terminal it should not work for them, forms should use CSRF tokens - and only authenticated user should have access
- as this will be small, you do not need database, file config for configuration should be enough ( the config would have hashed password and username, what can be set with command line flags used with the executable, for example
--new-user admin --password Admin123! - to change password
--change-password admin <some strong new password> - MFA would be possible to setup when user signs in to website, in their profile
- the config file if does not exists will be created on first run in same folder as is executable