Dashboard Guide
Every page of the PyQt6 operator dashboard: what it is for, what to try and what to watch for
The dashboard in dashboard/ is a PyQt6 desktop app that configures, deploys and operates both
stacks, on this machine or on remote hosts over SSH. It also acts as a teaching tool: every page has an in-app
guide (press F1), and the Knowledge Base page has guided labs. This page describes each page and the
setup flow around them. For the setup steps in order, see Getting Started.
Launching
cd dashboard
./run.sh
On the first run, run.sh creates venv/ by itself. You do not have to install
anything with pip by hand:
- If
notify-sendis installed, a desktop notification appears straight away. This matters when the app is started from the desktop launcher, where nothing else shows until Qt is available. - It creates the venv, upgrades pip and installs PyQt6 on its own.
- It opens a graphical progress window (
setup_progress.py) while the rest ofrequirements.txtinstalls (PyQt6-WebEngine, PyQt6-Charts).
On every launch, run.sh also checks the X11 keyboard layout (see
Troubleshooting) and then runs main.py. To rebuild the environment
from scratch, delete venv/ and run ./run.sh again.
Dashboard.desktop is an XDG launcher entry with Terminal=false. Its
Exec, Path and Icon lines contain absolute paths from the author's
machine. Change them to your checkout's path before copying the file to
~/.local/share/applications/.
First-Run Wizard
The wizard opens until a first run completes (on a fresh checkout, or after deleting state.json). To run it again, go to Connectors & Config →
Re-run setup wizard. A re-run loads the existing .env values rather than clearing them, so you
can use it to fix a single field. A step strip at the top of each page shows which steps are done, which one is
current and which are left.
| Step | What it does |
|---|---|
| Welcome | Introduction. Also shows the dependency banner if docker, the Compose plugin, ssh or rsync is missing. |
| Remote hosts (optional) | Marks ids and/or siem as remote and asks for each one's SSH host, port, user, key and remote path. |
| Edge .env | Edits ids/.env. For a local target with no .env yet, the form starts from .env.example. For a remote target, the file is fetched over SSH and saved back to the remote. A missing remote file gives an empty form. If the fetch fails, the local file is shown instead, with a note explaining why. |
| SIEM .env | The same for siem/docker/.env. |
| Certificates (optional) | Generate all certificates now creates the SIEM CA and service certificates, then the edge nginx certificate. You can also do this later on the PKI & Certificates page. |
| Done | Writes state.json and opens the main window. |
Warning Banners
Banners appear above every page, so a problem shows up on any page you are on.
- Missing dependency. Shown when docker or the Compose plugin is missing (both are required), or ssh or rsync is missing (needed only for remote features). The banner offers an install command for your distribution. The commands are listed under Prerequisites.
- Host settings. Shown when a host lacks a kernel setting that a stack needs but cannot set
for itself:
vm.overcommit_memory=1for Redis on the edge host, andvm.max_map_count=262144for Elasticsearch on the SIEM host. Every target in use is checked, including remote ones over SSH. The banner shows the commands that fix it.
Navigation
The left rail groups the pages into five sections. Each section shows its main pages and keeps the rest in an overflow list. You can edit the rail layout, and the View menu always lists every page.
| Shortcut | Action |
|---|---|
| Ctrl+K | Command palette: jump to any page by name. Also a toolbar button. |
| F1 | Help for the current page: what it is for, what to try, what to notice. |
| Ctrl+1…9 | Open the Nth visible page in the rail. |
| Ctrl+R | Refresh the current page. |
| Ctrl+F | Focus the Forensics Analysis search box. |
| Group | In the rail | In overflow |
|---|---|---|
| Overview | Overview | — |
| Monitor | Live Events, Global Visualization, SIEM Analytics | Log Pipeline, Workload Telemetry, Forensics Analysis |
| Threat Operations | Attack Simulation, Adversary Sessions, Network IDS (Suricata), Detection Policy | Pattern Database, Signature Simulation, Pool Scaling, Segmentation Validation, Pool State Store |
| Manage | Workloads, WordPress Studio, WordPress Update, Connectors & Config | PKI & Certificates, Backup & Recovery |
| Reporting | Knowledge Base | Reporting |
Pages that poll (Log Pipeline, Pool Scaling, Workload Telemetry) refresh only while they are visible. Docker, SSH and Redis calls run on background threads, so a slow or unreachable remote host does not freeze the window.
Overview
The landing page. It shows the current risk score, one health line for each stack and a list of recent
security events. It takes its data from the shared docker compose ps poller and the app-wide
security-event feed, so it starts no background work of its own. The quick-action tiles jump to the relevant
page.
Monitor
Live Events
A stream of every decision the reverse proxy's pattern analyzer makes. It does not depend on Kibana or the
SIEM. Each request writes a burst of log lines (scoring signals, routing steps, the final score and one
outcome line), and the page collapses each burst into a single row with the outcome, the final score,
the signals that fired and the request latency. When first opened, it fills in recent history from one
docker compose logs read.
Global Visualization
A diagram of both stacks' containers and how they connect, with a details panel for the selected node.
| Colour / state | Meaning |
|---|---|
| healthy | Running with a passing healthcheck. |
| running | Running; the service has no healthcheck. |
| unhealthy | Running but failing its healthcheck. |
| exited (ok) | A one-shot job that finished with exit code 0, such as a seed or init job. |
| exited (bad) | Exited with a non-zero code. |
| created (amber) | Created but not started. |
| down | No container. |
- Nodes show uptime. A red !N badge counts the log lines that contain
erroror a word starting withfailorfault(case-insensitive). Click the badge to see only those lines, read with--tail=all. - Each node has two quick icons: ⬇ exports its logs to a file, and ↗ opens its web UI.
- The details panel has Restart, View logs, Open web UI and Open shell.
The shell runs
docker exec -it … sh -c 'exec bash || exec sh', over SSH for remote targets.
A green vector_outbound node only means the container is running. It does not show whether logs
are reaching the SIEM; use Log Pipeline for that.
SIEM Analytics
An embedded browser that opens Kibana at https://<SIEM host or localhost>:5601/. You can
edit the address bar.
- Autologin fills in Kibana's login form with the SIEM stack's
ELASTIC_USERNAME/ELASTIC_PASSWORD. If it cannot read them, it does nothing and the normal login form stays usable. - Remember credentials (on by default) keeps a persistent browser profile, so you stay logged in across restarts. Every other embedded browser in the app uses a private (off-the-record) profile.
- Bookmarks open the saved dashboards (Attack Patterns, Threat Decisions & Decay) and Discover. Export PDF… saves a full-page screenshot of every bookmarked page, each with a short explanation of what it shows. See Kibana Dashboards.
Log Pipeline
Shows whether the edge's Vector shipper is actually delivering logs to the SIEM. It combines four checks:
shipping is configured (ELK_ENABLED / VECTOR_HOST), the shipper container is running,
its recent log has no delivery errors since its last passing healthcheck, and vector_inbound is
running on the SIEM side. It refreshes every 15 s. To check it works, stop vector_inbound
and the page should turn to failing.
Workload Telemetry
Live resource use per container for the selected target, in an htop-style table: CPU, memory, PIDs, network and block I/O, and on-disk log size. Three graphs show CPU %, memory and log size over time, with one line per container plus a bold average line. Attack markers make it easy to see what a scenario cost.
Forensics Analysis
A grep-style search across all containers of every configured target at once, local and remote. It runs
docker compose logs --tail=N for each selected target and keeps docker's per-service colours in
the results. Matching is done on the text with colour codes removed, so a code cannot split a search term.
Options:
- Regex mode, a time range (docker's
--since) and search history. - Named saved searches.
- Collapsing repeated lines into one (×N).
- Export to plain text or JSON Lines.
Threat Operations
Attack Simulation
An embedded browser on the shop, a pattern-preset dropdown and a live pattern-analyzer log. The proxy routes the browser like any other visitor, so a request may end up on production or on a honeypot pool.
- Run pattern (curl) sends the preset's real request, with its headers and body. Run pattern (browser) opens the preset's URL in the embedded browser as a plain GET, using the browser's current session. These are separate buttons on purpose: an earlier version sent both requests from one click, and the log showed two different signal profiles for what looked like a single run.
- What is this? explains the selected preset.
- The Pattern analyzer tab shows a timeline of colour-coded event cards, newest first. Tick some cards and use Copy selected to copy them as text with their real log timestamps.
- A Postman-style request builder (method, URL, headers, body) can be filled from a preset, edited, and sent with curl. It shows the raw status, headers and body.
- Reset local score + cookies clears the embedded browser's cookie jar. Unpoison host IP clears the IP reputation that your own test runs have built up for your host.
Adversary Sessions
Lists every proxy session (session:* in session_store) with its IP, risk score,
request count, verdict and honeypot pool. For the selected session it shows a plain-language summary, the IP's
reputation entry, and a timeline of the suspicious requests that built up its score.
Network IDS (Suricata)
Two tabs. Alerts shows recent eve.json alerts with counts by severity, top signatures
and top source IPs. Rules lists local.rules with sid, message, class and state. You can
switch rules off or on (they are commented out in the file) and save, which restarts Suricata to load the
edited file. See Suricata Network IDS.
Detection Policy
A form for the edge .env settings that decide who gets diverted, so you do not have to edit the
raw file. It covers score decay and half-life, IP-reputation weight and shared-address handling. Each value is
checked before saving. Only the changed keys are written back, and comments in the file are kept. A sentence
under the form explains what the current decay settings do to a maxed-out score. nginx reads these values at
startup, so the page offers to restart reverse_proxy after saving.
Pattern Database
A browsable, filterable catalogue of every pattern: Lua CVE patterns, generic signatures, header and upload
rules, scanner rules, Attack Simulation presets and Suricata SIDs. Select a row to see its trigger, source,
score path and lesson. The catalogue is read from patterns/patterns.json, the same file this
documentation site uses (see Pattern Database). The checkboxes and the
add / edit / duplicate / remove / revert / export actions change only the plugin registry
(patterns/registry.json). A pattern switched off here is also dropped from Attack Simulation and
Segmentation Validation runs.
Signature Simulation
Follows one browser characteristic, the screen size, all the way to the proxy's consent-gated, one-way
gdpr_signature. You can resize the mock browser window on the left, and its size is the value that
gets signed. Five stages are shown on the right. The two client-side stages (collect the characteristics,
RSA-encrypt them into a gdpr_token) are reproduced in full. The two server-side stages (append the
client IP, hash with a secret salt) are described but not shown, because only the resulting signature ever
leaves the proxy. To see the idea at work, resize the window and run again: the signature changes, and
returning to an earlier size gives the earlier signature back. See
Device & GDPR Signature.
Pool Scaling
Shows the honeypot pool registry without running a test or reading raw Redis keys. It covers:
- the pool count and the state of each pool;
- the resource budget in use (memory, CPU, pool cap) and the reason growth stopped;
- each pool's sessions and idle time;
pool_manager's recent build, hand-off and scale-down events.
Segmentation Validation
Opens 3 to 10 embedded browsers, each with its own private profile and cookie jar, to show how pools handle several users at once. A cookie-less request is matched to a session by a passive fingerprint, so each window also gets its own User-Agent suffix and Accept-Language; otherwise the proxy would see them as one client.
- Open shop in all loads the shop in every window. Attack from all sends the same pattern from each window. Refresh pool state re-reads the pools.
- Once a window's score passes the threshold, its session is bound to a pool.
pool_managerbuilds one pool per session until it reaches its resource limit; after that, sessions share pools round-robin. - In the database-proxy layer, one production shop serves every window and each diverted session goes to its own honeypot database. The run then offers only the patterns that layer isolates, and tells windows apart in each database's MySQL query log by their WooCommerce session key.
- The run can be saved as a PDF report that includes pool memory and CPU use over time, showing pools being built and later scaled down.
Pool State Store
Every key in the edge Redis (session_store): sessions, threat_ips,
suricata_alerts and the rest. The table shows each key's type, TTL and size; click a row to see
the full value. A bar chart shows the current threat_ips score for each IP. A dropdown chooses the
local or remote edge target. The key layout is described in
Lua Internals.
Manage
Workloads
Start, restart, stop and purge each project, local and remote, with the live status next to the buttons and the command output below.
- A progress bar follows a start. The "all N up" count includes one-shot jobs that exited with code 0.
- The log tail runs all the time. It also feeds the error badges on Global Visualization, so those keep counting whichever page is open. Download logs saves it to a file.
- Purge runs
docker compose down -v, which deletes the project's volumes, so it asks for confirmation first. - The Honeypot layer dropdown chooses between the WordPress-proxy level (a separate decoy stack per session) and the Database-proxy level (one shop, a decoy database per session). See Honeypot Layers.
- You can save a start or stop as a PDF report, with Global Visualization screenshots and warnings from any failed seed jobs. See Service Start/Stop Reports.
WordPress Studio
The production wp-admin, embedded, plus a button that copies your changes out to every honeypot pool, with a
progress bar and a status row per pool. The embedded browser adds the studio passthrough headers and the
internal-test secret to every request, so nginx always sends wp-admin to production and never diverts an edit
into a honeypot. The copy step runs the same allow-listed script as honeypot_content_sync
(--once N). It copies pages, posts, products and safe settings. It never copies user accounts,
orders or secrets. See WordPress Management.
WordPress Update
Checks for newer WordPress core and WooCommerce versions, then upgrades every instance in five steps:
- Turn the maintenance page on. This is a Redis flag with a TTL; while it is set, the edge returns 503.
- Update production's files and database.
- Re-sync the files into every pool volume.
- Migrate each static pool's database.
- Turn the maintenance page off.
If maintenance mode cannot be turned on, the run stops before touching production. Once it is on, a failed step does not stop the run; each failure is reported on its own row. The flag is always cleared at the end, and its TTL brings the site back even if the dashboard crashes mid-update.
Connectors & Config
- .env editor for both projects, with a Local / Remote switch (a remote file is edited over
SSH). Secrets are masked and have a Generate button. Refresh reloads the file. Keys that
exist in
.env.examplebut not in your.envare marked (new, from .env.example), which shows what an update added. - Remote targets: see below.
- General tab: the status poll interval, and tray notifications. When these are on, the tray icon alerts you when a container becomes unhealthy or exits with an error.
- Export / import of the whole configuration as one JSON file.
- Re-run setup wizard.
The export file includes both .env files in plain text: database, Redis, Elastic and
signing secrets. Treat it like the .env files themselves.
PKI & Certificates
Regenerates certificates: all of them, the SIEM CA and every service certificate, a single service's
certificate, or the edge nginx self-signed certificate. The vector-agent certificate is copied to the edge
automatically. Generate certificates before the first start. The edge certificate is self-signed, so use
curl -k or accept the browser warning.
Backup & Recovery
Lists the database dumps and WordPress file archives that backup_service writes under
/backups, plus the end of its backup.log. From here you can:
- restore either kind of backup onto the live production stack;
- label (rename), delete, export or import a backup;
- use Reset demo store, which re-runs the seed script (
scripts/seed_production_db.sh) to rebuild a clean WooCommerce/Elementor shop after patterns have been run against it.
ids/backups/manage_backups.sh does the same from the command line and shares the same
labels.json labels file.
Reporting
Knowledge Base
The dashboard's teaching layer, with four tabs:
- Start here: how the system works in five steps, plus a tour of every page with links that open it.
- Guided labs: checklists that walk through the pages. Ticked steps are saved.
- Glossary: searchable terms.
- Pattern lessons: one per preset, covering the attack class, OWASP Top 10, MITRE ATT&CK mapping, how the attack works and how to defend against it.
| Lab | Covers |
|---|---|
| 1. Bring the system up | Generate certificates, start ids then siem on Workloads, wait for every node in Global Visualization to turn green, then read the glossary entries for Honeypot, Reverse proxy and SIEM. |
| 2. Watch a normal visitor | Reset the local score, browse the shop in Attack Simulation, and check that the requests route to PRODUCTION with a low score. |
| 3. Fire an SQL injection | Run the CVE-2024-27956 (WP Automatic SQLi) preset with curl, read each signal and its points, check that the result is HONEYPOT, then find the session's score in Pool State Store. |
| 4. Investigate in the SIEM | Find the CVE under Top CVEs Detected in Attack Patterns, filter Discover by your IP, then search the raw logs for the CVE ID. |
| 5. Tune the detector | Divert the browser, wait one half-life (five minutes: 100 decays to 50, below the threshold) and watch it return to production. Then repeat with THREAT_DECAY_ENABLED=false and think about why never forgiving a score causes false positives. |
| 6. Divert sessions and watch the pools | Note the pool budget, attack from every Segmentation Validation window, check that each session gets a different pool, then read the build and hand-off events in Pool Scaling. |
| 7. Switch the honeypot layer | Run the same CVE with the WordPress-proxy layer and then with the Database-proxy layer, and compare which attack types each layer can isolate. |
| 8. Derive a device signature | Derive a signature, resize the window and derive again, then return to the first size. The first signature comes back, which is how a visitor is recognised again after clearing cookies. |
Reporting
One-click PDF exports: an auto-generated "Implementation" chapter built from excerpts of the live source tree, an architecture overview, and the Pattern/CVE matrix. A preview lists what will be included; entries whose source file is missing in your checkout are skipped.
Remote Targets
Each project (ids, siem) can run locally or on a remote host. Set the host, port,
user, SSH key and remote path in Connectors & Config, then use Test connection.
- Upload .env to remote… copies just the
.envwithscp. - Upload entire project… copies the project with
rsyncand shows progress. Backups, logs and volumes are left out. If the remote directory is not empty, it asks before overwriting. This needsrsyncinstalled locally as well as on the remote. - Once a target is set up, every page that touches Docker or Redis (Workloads, shells, logs, Pool State Store, Suricata, Detection Policy, host-settings checks) runs its commands over SSH.
State and Settings Files
| File | Holds |
|---|---|
dashboard/state.json | Window geometry, the last open page, remote target settings, the poll interval, the tray toggle, the theme, the rail layout, the honeypot layer choice, Forensics search history and saved searches, recent security events and completed lab steps. It is gitignored and contains no .env contents. Delete it to get the first-run wizard again. Older files still load: keys the app does not recognise are ignored, and missing keys fall back to their defaults. |
ids/.env, siem/docker/.env | The real configuration. The dashboard edits these directly, or the remote copies over SSH. |
dashboard/venv/ | Created by run.sh. Safe to delete. |
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| The app aborts at startup inside QtWebEngine on X11 | The X11 keyboard layout/variant cannot be compiled by xkeyboard-config (for example layout sk with variant qwertz), and QtWebEngine treats that as fatal. run.sh detects this and falls back to the layout with no variant, printing a warning. If you start main.py directly, run setxkbmap <layout> first. |
| Nothing happens when using the desktop launcher | The paths in Dashboard.desktop still point to the author's machine. Fix Exec, Path and Icon. On a first run, wait for the setup notification and the progress window. |
| Embedded browsers are blank or crash | Missing Qt/Chromium system libraries. See Prerequisites. |
| command not found for docker, ssh or rsync | Use the install command in the dependency banner, then restart the app. |
| Global Visualization is green but Kibana is empty | Open Log Pipeline. See also Runbooks. |