Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:The Overlord Network Kill Switch is a web service designed to provide a simplified, user-friendly interface for controlling network access within a home environment. It integrates with Apple's HomeKit via Homebridge to allow non-technical users to perform actions like blocking streaming services on a per-device basis or disabling internet access for specific devices. This is achieved by programmatically controlling Pi-hole DNS filters and Ubiquiti firewall rules. The system's primary goal is to simplify complex network management tasks, such as parental controls or setting up "focus time," into one-touch actions on an iOS device.
The architecture is composed of several loosely coupled components that communicate primarily through MQTT messages and RESTful API calls. A user's action in the HomeKit app triggers a chain of events that flows through Homebridge, an MQTT broker, a Node-RED instance for orchestration, and finally to a central FastAPI backend server. This server contains the core logic to interact with the Pi-hole and Ubiquiti Network Controller APIs, applying the requested network changes.
Sources: README.md:5-12, AGENTS.md:5-8, cgi-bin/controller.py:31-43
High-Level Data Flow
The system follows a clear, event-driven flow from user interaction to service execution. The user initiates an action (e.g., toggling a switch in HomeKit), which is translated into an MQTT message. Node-RED subscribes to these messages, parses them, and makes corresponding HTTP requests to the FastAPI server. The server then executes the command against the target service (Pi-hole or Ubiquiti). Status updates follow the reverse path to update the switch state in the user's HomeKit interface.
This diagram illustrates the main data flow from user action to service change and the subsequent status update.
Sources: README.md:104-126, AGENTS.md:9
Project Structure
The repository is organized into distinct directories for the web application, libraries, configuration, and examples.
├── cgi-bin/ # FastAPI application
│ ├── controller.py # Main app, config init, lifespan
│ ├── wsgi.py # WSGI entry point
│ └── gunicorn_config.py # Gunicorn settings
├── lib/
│ ├── pihole/ # Pi-hole integration
│ │ ├── base.py # BaseHTTPHandler base class
│ │ ├── pihole.py # PiHoleOverlord - domain blocking
│ │ ├── pihole_router.py # FastAPI routes for /pihole
│ │ └── alldns.py # MasterEnabler - global DNS toggle
│ └── ubiquity/ # Ubiquiti integration
│ └── ubiquity.py # UbiquitiOverlord - firewall/device control
├── etc/
│ ├── config.ini.sample # Configuration template
│ └── webserver_requirements.txt # Python dependencies
├── node_red_flows/ # Node-RED flow examples
└── pyproject.toml # Python project config
Sources: AGENTS.md:16-41
Components
1. Home Automation (HomeKit & Homebridge)
The user-facing component is Apple's HomeKit, which provides the switches on iOS devices. Homebridge acts as the bridge to connect non-native HomeKit devices. The homebridge-mqttthing plugin is used to create virtual switches that communicate via MQTT. Each switch is configured with topics for getting its current state (getOn) and setting its state (setOn).
An example homebridge-mqttthing configuration for a "HBO" switch:
{
"type": "switch",
"name": "HBO",
"debounceRecvms": 100,
"topics": {
"getOnline": "stat/dns_controller/master/service_status",
"getOn": "stat/dns_controller/media/hbomax/status",
"setOn": "cmnd/dns_controller/media/hbomax/change"
},
"accessory": "mqttthing"
}
Sources: README.md:14, README.md:67-78
2. Orchestration (Node-RED)
Node-RED serves as the orchestration layer. It subscribes to MQTT topics published by Homebridge, parses the incoming messages to determine the user's intent, and translates them into specific HTTP API calls to the backend FastAPI server.
The provided flow in node_red_flows/dns.json defines logic for three main types of commands:
- Media Control: Handles topics like
cmnd/dns_controller/media/+/changeto enable/disable domain-based blocks (e.g., streaming services). - Master Control: Handles topics like
cmnd/dns_controller/master/+to globally enable/disable Pi-hole DNS blocking. - Router Control: Handles topics like
cmnd/router_controller/change_rule/+to enable/disable Ubiquiti firewall rules.
This diagram shows the Node-RED logic for handling a Pi-hole media control request.
Sources: node_red_flows/dns.json
3. Backend Server (FastAPI)
The core of the system is a Python backend built with FastAPI and run by Gunicorn. It exposes a REST API for managing Pi-hole and Ubiquiti devices.
Sources: cgi-bin/controller.py, cgi-bin/gunicorn_config.py, cgi-bin/wsgi.py
Application Lifecycle
The application is initialized in cgi-bin/controller.py. A lifespan context manager handles startup and shutdown events.
- On startup:
- Reads configuration from
../etc/config.iniand environment variables. - Initializes the
PiHoleOverlord,MasterEnabler, andUbiquitiOverlordmodules if they are enabled. - Includes the API routers for Pi-hole and Ubiquiti.
- Publishes a "true" message to an MQTT Last Will and Testament (LWT) topic to indicate the service is online.
- Reads configuration from
- On shutdown:
- Calls the
shutdown()method on the Pi-hole and Ubiquiti controller objects to close sessions. - Publishes a "false" message to the LWT topic.
- Calls the
Sources: cgi-bin/controller.py:151-179
Configuration
Configuration is managed through etc/config.ini and supplemented by environment variables. The init_config function in controller.py loads settings for Pi-hole, Ubiquiti, and MQTT.
| Section | Key | Description | Source File |
|---|---|---|---|
[general] | pihole_control_enabled | Enables/disables the Pi-hole control module. | cgi-bin/controller.py:60 |
[general] | ubiquiti_control_enabled | Enables/disables the Ubiquiti control module. | cgi-bin/controller.py:60 |
[general] | remote_pi_list | Space-separated list of Pi-hole IP addresses. | cgi-bin/controller.py:81 |
[block_domains] | (e.g., hbomax) | A list of regex patterns to block for a specific service. | cgi-bin/controller.py:76 |
[allow_domains] | (e.g., school_work) | A list of regex patterns to allow for a specific service. | cgi-bin/controller.py:76 |
[ubiquiti] | remote_ubiquiti_device | IP address of the UniFi controller. | cgi-bin/controller.py:99 |
[ubiquiti] | remote_ubiquiti_api_key | API key for the UniFi controller. | cgi-bin/controller.py:99 |
[ubiquiti_targets] | (e.g., kids_devices) | A group of MAC addresses to be controlled together. | cgi-bin/controller.py:106 |
[ubiquiti_rules] | (e.g., block_streaming) | Names of firewall rules to be controlled. | cgi-bin/controller.py:113 |
[mqtt] | broker, port, lwt_topics | MQTT broker connection details and LWT topics. | cgi-bin/controller.py:118 |
Sources: cgi-bin/controller.py:54-135, AGENTS.md:73-83
Core Logic Classes
The business logic is encapsulated in handler classes that manage communication with the target services.
This diagram shows the inheritance structure of the handler classes.
BaseHTTPHandler: A base class for Pi-hole handlers. It manages session creation and authentication for multiple Pi-hole instances using thepihole6apilibrary. It is initialized with the list of Pi-hole IPs and credentials.
Sources: lib/pihole/base.py:11-40PiHoleOverlord: Inherits fromBaseHTTPHandler. Manages adding and removing domains from Pi-hole's regex block/allow lists. It determines whether to use the block (deny) or allow (allow) list based on thedomain_blockname's presence in the configuration.
Sources: lib/pihole/pihole.py:21MasterEnabler: Inherits fromBaseHTTPHandler. Provides methods to globally enable or disable DNS blocking on all configured Pi-hole instances, with an optional timer for temporary disabling.
Sources: lib/pihole/alldns.py:21UbiquitiOverlord: Manages interaction with the Ubiquiti Network Controller API. It handles authentication (via API key), session management, and provides methods to change the state of firewall rules and block/unblock client devices by MAC address. It also includes a caching mechanism for firewall rules to improve performance.
Sources: lib/ubiquity/ubiquity.py:44
4. API Endpoints
The FastAPI server exposes several endpoints, which are organized by routers.
Sources: AGENTS.md:43-69, lib/pihole/pihole_router.py:38-83, lib/ubiquity/ubiquity.py:456-495
Pi-hole Domain Control (/pihole)
| Method | Path | Description |
|---|---|---|
GET | /status/{domain_block} | Check if a domain block is enabled. |
POST | /enable/{domain_block} | Enable a specific domain block list. |
POST | /disable/{domain_block} | Disable a specific domain block list. |
Pi-hole Global DNS Control (/alldns)
| Method | Path | Description |
|---|---|---|
GET | / | Get the global DNS blocking status. |
POST | / | Disable DNS blocking (with optional timer param). |
DELETE | / | Enable DNS blocking. |
Ubiquiti Control (/ubiquiti)
| Method | Path | Description |
|---|---|---|
GET | /status_rule/{target} | Get the status of a firewall rule. |
GET | /enable_rule/{target} | Enable a firewall rule. |
GET | /disable_rule/{target} | Disable a firewall rule. |
GET | /status_device/{target} | Get the block status of a device group. |
GET | /enable_device/{target} | Unblock a device group (set to "online"). |
GET | /disable_device/{target} | Block a device group (set to "offline"). |
GET | /refresh | Force a refresh of the firewall rule cache. |
Ubiquiti Firewall Rule Change Sequence
This sequence diagram details the process of disabling a firewall rule, starting from the user's action in HomeKit.