Troubleshooting Guide
Relevant source files
The following files were used as context for generating this wiki page:This guide provides information for diagnosing and resolving common issues with the Overlord Network Kill Switch. It covers problems related to configuration, the FastAPI web server, and integrations with Pi-hole, Ubiquiti, and MQTT/Node-RED. The primary goal of the project is to simplify network control for non-technical users via HomeKit, so ensuring each component works correctly is crucial.
The system uses a FastAPI server to expose an API that is called by Node-RED in response to MQTT messages from Homebridge. The server then interacts with Pi-hole and Ubiquiti APIs to perform the requested actions, such as blocking domains or disabling firewall rules.
Architecture and Data Flow
Understanding the system's architecture is the first step in troubleshooting. An issue can occur at any point in the chain from the user's action in HomeKit to the execution on the target service.
This diagram illustrates the data flow from a user's action in HomeKit to the final service change.
Sources: README.md:100-121, AGENTS.md:7-9
Configuration Issues
Incorrect configuration is a common source of errors. The application uses a combination of an ini file and environment variables.
Sources: cgi-bin/controller.py:60-163, README.md:36-44
Configuration Loading
The main configuration is loaded from ../etc/config.ini by the init_config function in controller.py. This function parses settings for Pi-hole, Ubiquiti, and MQTT, and can use environment variables as fallbacks for certain values.
Sources: cgi-bin/controller.py:60-62
Environment Variables
These variables are typically set in an envfile when running the container.
| Variable | Description | Example |
|---|---|---|
DNS_SERVERS | Comma-separated list of DNS server IPs. | 192.168.1.53,192.168.1.54 |
REMOTE_PI_PASSWORD | The admin password for your Pi-hole instances. | your_pihole_password |
REMOTE_PI_LIST | Space-separated list of Pi-hole IP addresses. | "192.168.1.53 192.168.1.54" |
MQTT_BROKER | IP address of the MQTT broker. | 192.168.1.100 |
MQTT_PORT | Port for the MQTT broker. | 1883 |
REMOTE_UBIQUITI_DEVICE | IP address of your UniFi controller/device. | 192.168.1.1 |
REMOTE_UBIQUITI_API_KEY | The API key for your UniFi controller. | your_unifi_api_key |
Sources: README.md:37-43, AGENTS.md:83-89, cgi-bin/controller.py:97-120
config.ini File
The config.ini file provides more detailed control over the application's features.
| Section | Key | Description |
|---|---|---|
[general] | pihole_control_enabled | Set to true to enable Pi-hole integration. |
[general] | ubiquiti_control_enabled | Set to true to enable Ubiquiti integration. |
[general] | mqtt_announce_enabled | Set to true to publish service status (LWT) to MQTT. |
[block_domains] | hbomax | A list of regex patterns to block for the "hbomax" group. Each key in this section defines a new block group. |
[allow_domains] | school_work | A list of regex patterns to allow for the "school_work" group. |
[ubiquiti_targets] | kids_devices | A list of MAC addresses to control as a group. |
[ubiquiti_rules] | Block-Streaming | A list of firewall rule names to be managed. |
[mqtt] | lwt_topics | A list of MQTT topics to publish a "last will and testament" message. |
Sources: cgi-bin/controller.py:67-151, AGENTS.md:92-99
Troubleshooting Steps:
- Verify that
pihole_control_enabledandubiquiti_control_enabledare set totrueinconfig.iniif you intend to use these features. - Ensure that IP addresses, passwords, and API keys are correct.
- Check that the domain groups (
[block_domains]) and Ubiquiti targets/rules are correctly defined. The names used here must match the names used in your Node-RED flows and HomeKit configuration.
FastAPI Server
The core of the application is a FastAPI server, typically run with Gunicorn.
Sources: cgi-bin/controller.py, cgi-bin/wsgi.py, cgi-bin/gunicorn_config.py
Server Startup
The application is started via wsgi.py, which uses uvicorn to run the FastAPI app instance from controller.py. The lifespan function in controller.py is critical as it initializes all modules (Pi-hole, Ubiquiti) and includes their respective API routers.
# cgi-bin/controller.py:166-180
@asynccontextmanager
async def lifespan(app: FastAPI):
config_file = os.path.join(os.path.dirname(__file__), "../etc/", "config.ini")
app_config = init_config(app, config_file)
# ...
if app_config["pihole_control_enabled"]:
pihole_router.init(app_config)
app.include_router(pihole_router.main_router)
app.include_router(pihole_router.alldns_router)
if app_config["ubiquiti_control_enabled"]:
ubiquity.init(app_config)
app.include_router(ubiquity.router)
# ...
yield
# ... shutdown logic ...
Troubleshooting Steps:
- Check the container logs for any errors during startup. Errors in
init_configor thelifespanfunction will prevent the server from starting correctly. - Access the root endpoint (
/) of the server (e.g.,http://<server_ip>:19000/). It should return{"status":"alive"}. - Access the OpenAPI documentation at
/docsto see all available endpoints and test them directly.
Component-Specific Troubleshooting
Pi-hole Integration
Pi-hole control is managed by classes in the lib/pihole/ directory and relies on the pihole6api library.
Sources: lib/pihole/base.py, lib/pihole/pihole.py, lib/pihole/alldns.py
Connection Flow
The BaseHTTPHandler.first_connect method establishes a session with each Pi-hole instance defined in REMOTE_PI_LIST.
This diagram shows the sequence for enabling a domain block.
Troubleshooting Steps:
- Authentication: Ensure
REMOTE_PI_PASSWORDis correct. Thefirst_connectmethod inlib/pihole/base.pywill fail if the password is wrong. - Inconsistent State: The
MasterEnablerandPiHoleOverlordclasses check for consistent states across multiple Pi-hole instances. If one Pi-hole is enabled and another is disabled, the API may return an{"status": "unknown"}. Check the logs for warnings about inconsistent states.
Sources: lib/pihole/alldns.py:70-74 - Domain Groups: Verify that the domain block name (e.g.,
hbomax) exists as a key under[block_domains]or[allow_domains]inconfig.ini. If not, the API will return an error.
Sources: lib/pihole/pihole.py:85-86
Ubiquiti Integration
Ubiquiti control is handled by the UbiquitiOverlord class. It manages firewall rules and device blocking.
Sources: lib/ubiquity/ubiquity.py
Connection and Authentication
Connection to the Ubiquiti controller now uses an API key, which simplifies authentication. The first_connect method sets up the session with the required X-API-KEY header.
# lib/ubiquity/ubiquity.py:202-207
def first_connect(self):
# ...
if self.ubiquiti_api_key is None or self.ubiquiti_api_key == "":
raise HTTPException(status_code=401, detail="API Key not set")
self.session = requests.session()
self.session.headers.update({"X-API-KEY": self.ubiquiti_api_key})
self.logged_in = True
Firewall Rule Management
The system caches firewall rules for performance, with a default TTL of 60 seconds. A request to change a rule first checks if the cache is fresh (check_rules_freshness) and then sends a PUT request to the /firewall-policies/batch endpoint.
This diagram shows the process of disabling a firewall rule.
Sources: lib/ubiquity/ubiquity.py:361-404
Troubleshooting Steps:
- API Key: Ensure the
REMOTE_UBIQUITI_API_KEYis correctly set. A missing or invalid key will result in a 401 Unauthorized error. - Rule Names: The rule name specified in the API call (e.g.,
Block-Streaming) must exactly match a rule name defined in the[ubiquiti_rules]section ofconfig.iniand on the UniFi controller itself. - Rule Cache: If a rule was changed directly on the UniFi controller, the application might have a stale state. You can force a refresh by calling the
GET /ubiquiti/refreshendpoint.
Sources: lib/ubiquity/ubiquity.py:504-508 - Controller Version: The API endpoints used are for modern UniFi controllers (tested on 9.4.19). If you are on a very old version, the API paths might be different, causing requests to fail.
Sources: README.md:29, lib/ubiquity/ubiquity.py:133-135
Node-RED and MQTT
Node-RED acts as the bridge between MQTT messages from HomeKit and the FastAPI server's REST API. The example flow node_red_flows/dns.json contains the logic for this translation.
Sources: node_red_flows/dns.json, README.md:70-97
Flow Logic
The flow listens on specific MQTT topics, parses the topic and payload, and constructs the appropriate HTTP request to the FastAPI server.
This flowchart shows the logic for handling a media-related DNS change request.
Sources: node_red_flows/dns.json:115-144
Troubleshooting Steps:
- MQTT Topics: Ensure the topics in your Homebridge
config.jsonmatch the topics listened to by themqtt innodes in Node-RED. For example,setOn: "cmnd/dns_controller/media/hbomax/change".
Sources: README.md:76-78, node_red_flows/dns.json:15-28 - Node-RED Endpoint: The "Common Parsing" nodes in the flow have a hardcoded endpoint URL (
http://XXXX:19000). You must change this to the correct IP address and port of your FastAPI server.
Sources: node_red_flows/dns.json:428-433 - Debugging in Node-RED: Use the
debugnodes in the flow to inspect the message object (msg) at various stages. This will show you the parsed topic, the constructed URL, and the response from the FastAPI server.
Sources: node_red_flows/dns.json:29-42
Logging
Enabling detailed logging is crucial for debugging.
- FastAPI Server: The default log level is
INFO. You can change this incgi-bin/controller.pytologging.DEBUGfor more verbose output.
Sources: cgi-bin/controller.py:31 - Ubiquiti Module: The
UbiquitiOverlordclass has extensive debug logging. Setting the application's log level toDEBUGwill enable these messages.
Sources: lib/ubiquity/ubiquity.py:112-113 - Pi-hole Module: The Pi-hole classes also use the application's logger. Setting the level to
DEBUGwill show connection attempts and API call details.
Sources: lib/pihole/base.py:41-42 - Gunicorn: The Gunicorn configuration
cgi-bin/gunicorn_config.pysends access logs to standard output (accesslog = "-"), which is useful for seeing incoming requests.
Sources: cgi-bin/gunicorn_config.py:5