Installation takes under 2 minutes and requires only Docker. Find detailed answers about requirements, first-login setup, platform differences, and common blockers — as well as deep dives into traffic profiling, VyOS impairment scripting, multivendor security profiles, and Prisma SD-WAN API integration.
Yes — truly one command. The recommended way is the install script documented in the Quick Start section:
curl -sSL https://raw.githubusercontent.com/jsuzanne/stigix/main/install.sh | bash
That's it. The script automatically:
jsuzanne/stigix:stable image (~500 MB on first run)Dashboard is live at http://localhost:8080 within 30 seconds. Default login: admin / admin — change it immediately after first login.
Windows: The script doesn't run in PowerShell — follow the Windows Installation Guide.
Only two things are strictly required:
No Python, Node.js, or any other runtime needs to be installed on the host. Everything runs inside the container. The only prerequisite is Docker itself.
Supported platforms: Linux (bare metal, VM, Raspberry Pi 5, Intel NUC), macOS (Apple Silicon and Intel), Windows (via WSL2 + Docker Desktop), AWS EC2 / Azure VM.
Linux (Ubuntu / Debian):
curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER # then log out and back in
macOS: Download Docker Desktop or OrbStack. Both provide Docker Engine and Docker Compose out of the box.
💡 Pro Tip for Mac users: OrbStack is fully supported and recommended on macOS. It is significantly lighter, faster, consumes much less CPU/RAM, and starts up instantly compared to Docker Desktop.
Windows: Install Docker Desktop with WSL2 backend enabled. This is the recommended path — no manual WSL2 setup needed in recent versions.
Verify Docker is fully operational before installing Stigix:
# 1. Check Docker Engine version (must be 20.10+) docker --version # Expected: Docker version 24.x.x, build ... # 2. Check Docker is running (daemon reachable) docker info | grep "Server Version" # Expected: Server Version: 24.x.x # Error here = Docker daemon not started (open Docker Desktop or: sudo systemctl start docker) # 3. Check Docker Compose is available (critical for Stigix) docker compose version # Expected: Docker Compose version v2.x.x # If this fails, try the legacy command: docker-compose version # 4. Quick smoke test (pull and run a minimal image) docker run --rm hello-world # Expected: "Hello from Docker!" message
If all four commands succeed, Docker is ready and you can proceed with the Stigix install command.
Yes. The Stigix image is published for both AMD64 and ARM64. A Raspberry Pi 5 (4 GB RAM) with Ubuntu Server 24.04 is a common and well-tested deployment target for branch lab environments.
A Raspberry Pi 4 (2 GB) works for basic traffic generation and security testing but may run tight if you enable IoT simulation simultaneously. Pi 5 with 4–8 GB is the sweet spot for full-feature lab use.
Docker pulls the correct architecture automatically — no flag needed.
This affects IoT simulation and advanced traffic generation only — for everything else (dashboard, security tests, digital experience probes, convergence tests) both modes work identically.
The install script auto-detects your platform and selects the right compose file. On macOS/Windows you can still demo everything except Layer 2 IoT behavior.
Check these three things in order:
# 1. Is the container running at all? docker ps # Look for a container named "stigix" with status "Up" # 2. Check the startup logs docker compose logs stigix --tail=30 # Look for "Server listening on port 8080" # 3. Is something else already on port 8080? sudo lsof -i :8080 # macOS / Linux netstat -ano | find "8080" # Windows
If port 8080 is taken, add a .env file with PORT=8081 and update the port mapping in docker-compose.yml from "8080:8080" to "8081:8080", then restart.
If docker ps shows the container as Exited, the logs will explain why — most common causes are a missing .env variable or a permissions issue on the config directory.
A lot. On first start, Stigix auto-generates everything it needs with zero manual intervention:
config/applications-config.json is created automatically with a realistic enterprise mix: Microsoft 365 (Outlook, Teams, SharePoint, OneDrive), Google Workspace, Salesforce, Zoom, Slack, Workday, and more.config/interfaces.txt is populated with your primary interface (eth0, en0, ens4, etc.) detected from the host.config/users.json is created with a bcrypt-hashed admin/admin credential.Services that start active by default:
Services that require configuration before starting:
In short: open the dashboard and you'll see traffic flowing and probes running within the first minute, with no configuration required.
admin/admin credentials immediately.eth0, enp0s3). Run ip addr show on the host if you're unsure which one. Traffic generation won't start without this.Everything else (probes, security tests, VyOS routers, API keys) can be configured incrementally as you need each feature.
For most features — no. As long as the host running Stigix has internet connectivity through the SD-WAN path you want to test, traffic generation, security tests, digital experience probes, and convergence tests all work fine.
For IoT simulation in host mode (DHCP fingerprinting), Stigix must be on the same L2 broadcast domain as the SD-WAN router's LAN interface — so the simulated DHCP requests are seen by the router and its IoT classification engine.
A simple and common setup: Stigix runs on a laptop or SBC plugged into the branch LAN behind the SD-WAN router, with a default gateway pointing to the router. That's all you need for a complete lab.
Yes. The install script handles everything — Docker check, platform detection, compose file download, and startup:
curl -sSL https://raw.githubusercontent.com/jsuzanne/stigix/main/install.sh | bash
It auto-detects your platform (native Linux → Host Mode, macOS/WSL2 → Bridge Mode), asks you to choose a deployment mode, pulls the image, and starts the container. Dashboard is live at http://localhost:8080 in under 30 seconds.
You can also bypass the interactive prompt with a flag:
# Source + Target mode (recommended for labs) curl -sSL .../install.sh | bash -s -- --mode both # Target only (for DC/hub nodes) curl -sSL .../install.sh | bash -s -- --mode target # Dry run (preview without executing) curl -sSL .../install.sh | bash -s -- --dry-run
Windows users: The install script doesn't run in PowerShell — follow the Windows Installation Guide instead.
Always both, always simultaneously. Every Stigix instance — branch, DC, cloud — is a sender and a responder at the same time. This is not a mode you configure; it is the fundamental architecture of the platform.
Concretely, every running instance:
This means you can point any branch node at a DC node and run tests immediately — without touching any configuration on the DC side. The responder services start automatically.
In practice, a node deployed centrally (DC or cloud) will be used mostly as a responder because branch nodes send their tests toward it. But it is still fully capable of generating traffic outbound if needed. There is no "responder-only" mode to configure — that's just how you use it.
The install script's --mode both/source/target flag simply controls which ancillary services are included in the Docker compose file — it does not change the core sender+responder behaviour of the container itself.
Yes — all configuration and logs live in Docker named volumes (stigix_config and stigix_logs), which persist independently of the container lifecycle. Pulling a new image and restarting does not touch your data.
Stigix also supports State Persistence for running services. In Settings → System Info, each service (Traffic, Probes, IoT, Voice) has a toggle. When enabled, the service resumes exactly its pre-restart state automatically — so if traffic generation was running before a restart, it comes back running without manual intervention.
Default states: Traffic ON, Probes ON, IoT OFF (requires config), Voice OFF (requires server).
Proxmox LXC containers restrict low-level network operations by default. Stigix needs NET_ADMIN and NET_RAW Linux capabilities for Scapy-based IoT/Voice simulation (raw socket access for DHCP, ARP, and RTP injection).
Add these capabilities to your docker-compose.yml:
services:
stigix:
cap_add:
- NET_ADMIN
- NET_RAW
For a trusted lab environment where isolation is less of a concern, you can also use:
privileged: true
Warning: privileged: true gives the container full host access — only use it in isolated lab setups, never in production or shared environments.
Three quick checks in order:
# 1. Container status — look for (healthy)
docker compose ps
# Expected: stigix ... Up N minutes (healthy) ... 0.0.0.0:8080->8080/tcp
# 2. Health API endpoint
curl http://localhost:8080/api/health
# Expected: {"status":"healthy","version":"1.x.x"}
# 3. Interactive CLI (optional deeper check)
docker exec -it stigix stigix-cli
# Then run: auth login → admin/admin → status
You can also confirm auto-generated config was created:
# 67 applications should be listed jq '.applications | length' config/applications-config.json # Expected output: 67 # Auto-detected network interface cat config/interfaces.txt
If the health endpoint returns 200 and the container is marked (healthy), everything is running correctly.
The Traffic Generator creates continuous background HTTP/HTTPS traffic simulating realistic enterprise user activity — Microsoft 365, Google Workspace, Zoom, Salesforce, Slack, etc. It is designed to populate SD-WAN flow tables and trigger application-aware routing decisions.
Security Testing is entirely separate: it fires on-demand or scheduled one-shot requests to known malicious or policy-test URLs to validate that your security policies enforce correctly. The two engines use different config files, ports, and log files and run independently.
Feature Traffic Generator Security Tests Purpose Simulate user load Validate security policy Source config applications-config security-profile.json Execution Continuous loop On-demand / scheduled Log file traffic.log test-results.jsonl Stats stats.json Dashboard history
Weights are relative, not absolute percentages. The probability of an app being selected is app_weight / total_weight_of_all_apps.
{ "domain": "google.com", "weight": 100 } → 50% (100/200)
{ "domain": "microsoft.com", "weight": 50 } → 25%
{ "domain": "zoom.us", "weight": 50 } → 25%
The dashboard UI automatically recalculates and displays percentages as you edit weights. Useful ranges: 1–25 for background apps, 51–100 for regular business apps, 100–200 for dominant/demo apps (e.g. video streaming).
Prefix the domain with http:// to force plain HTTP (useful for internal servers). The engine uses HTTPS by default for all other entries.
{ "domain": "http://192.168.203.100", "weight": 50,
"endpoint": "/cgi-bin/hw.sh", "category": "Internal" }
You can also use raw IP addresses with HTTPS as long as the target serves a valid certificate. Multiple entries for the same domain with different endpoints are fully supported to distribute load across API paths.
Traffic profiles are stored in config/applications-config.json. Go to Settings → Traffic Distribution and use the Export button (top-right) to download the full JSON file. To import it on another Stigix instance, click the Import button next to it — no restart required.
For CLI-based workflows, the Stigix CLI supports profile management:
stigix-cli profile export --output my-profile.json stigix-cli profile import --file my-profile.json
Profiles are self-contained JSON files that travel easily between lab, PoC, and demo environments.
Three methods to confirm live traffic:
cat logs/traffic.log | tail -f streams live request outcomes.cat logs/stats.json | jq '.requests_by_app' shows actual distribution vs configured weights.If the counters are frozen, verify that traffic generation is toggled on in the dashboard, the correct network interface is selected, and the container is running (docker ps).
Start with the pre-built Enterprise Profile template available in Settings. It includes Microsoft 365 (Outlook, Teams, SharePoint, OneDrive), Google Workspace, Zoom, Salesforce, Slack, and Workday with realistic weights.
Recommended weight tiers for enterprise demos:
Consumer or shadow IT profiles (streaming, gaming, social media) use weights of 150–200 to dominate the mix and clearly show QoS and policy impact on the SD-WAN flow table.
Stigix supports 7 probe types, each using the native OS binary for accuracy:
curl to measure DNS lookup, TCP handshake, TLS handshake, and TTFB separately. Best for SaaS app health.ping for round-trip time. Score 100 if <100ms, reaches 0 at 500ms.dig (bypasses OS cache) to measure raw nameserver resolution. Score 100 if <80ms, reaches 0 at 400ms.nc (netcat) to test port reachability and handshake timing.iperf3 -u to measure jitter and packet loss. Score = 100 - (loss% × 10) - jitter_penalty. 10% loss = score 0.curl telemetry (DNS/TCP/TLS/TTFB). Timeout 15s.Default polling frequency depends on the probe type: HTTP, HTTPS, and Cloud probes default to 300 seconds (5 min); PING, TCP, UDP, and DNS probes default to 60 seconds. All are configurable from 30s to 3600s per probe. HTTP/HTTPS probes use a longer default because they run up to two sequential curl calls (timing metrics + optional content match body), and a shorter frequency can cause queue congestion when many probes are active simultaneously.
Navigate to Settings → Synthetic Probes → Add New Probe (or click Configure New Probe in the Digital Experience tab). Fill in:
HQ-GATEWAY or OFFICE365-UDPgoogle.com), socket (1.1.1.1:53), or IPProbes start running immediately after saving — no restart needed. The probe appears in the Digital Experience dashboard within one polling cycle.
To monitor an internal server with plain HTTP: set type to HTTP and target to http://192.168.1.10 (with explicit protocol prefix).
All probes return a score from 0 to 100. The dashboard stores minimum, maximum, and average over time.
Score Rating Meaning 80–100 Excellent No user impact 50–79 Fair Noticeable latency / jitter 1–49 Poor Severe degradation 0 Critical Unreachable or HTTP 5xx
HTTP/HTTPS scoring: 100 - (30% × latency_penalty + 35% × TTFB_penalty + 25% × TLS_penalty). Heavily penalised if latency >2s, TTFB >1s, or TLS >800ms.
An endpoint transitions to FLAKY when it fails but recently succeeded, and to DOWN after multiple consecutive failures — helping distinguish transient blips from hard outages.
Cloud probes target the Stigix Cloudflare Worker infrastructure and are available to all deployments without any configuration. Unlike custom probes (which you define against your own endpoints), Cloud probes hit Stigix-managed infrastructure on shared global POPs. They simulate specific scenarios useful for SD-WAN and SASE validation:
/saas/info) — Returns your public IP, country, and Cloudflare POP. Essential to prove which SASE egress point is in use and that traffic is flowing through the expected tunnel./saas/slow) — Simulates a 5-second backend delay. Score 100 if <200ms, 0 at 5s. Ideal for demonstrating latency impact of sub-optimal path selection./saas/flap) — Alternates between 0s and 5s delay every 60 seconds. Creates a square-wave pattern in your probe graph — useful for validating alerting thresholds and showing the dashboard reacting to periodic SaaS degradation./saas/wave) — Smoothly oscillates latency up to 5s over a 2-minute sine cycle. Produces a characteristic wave curve in the timing graph, useful for validating gradual path quality detection./saas/random) — 50% chance of a 5-second delay on each request. Simulates unpredictable SaaS degradation to validate that your SD-WAN path selection reacts to intermittent rather than sustained issues./download/large) — Downloads a 10 MB payload and scores on throughput. Score 100 if completed in <1s, 0 at 10s. Validates that the active WAN path delivers adequate bandwidth for bulk transfers./security/eicar) — Delivers the EICAR test string to check that IPS / Threat Prevention is blocking malware signatures on the active path.Advanced Stigix Probe — A builder option at the bottom of the dropdown lets you configure a fully custom cloud probe with granular parameters (mode, delay value, custom headers). Useful for scripting specific latency thresholds for a particular customer scenario.
All Cloud probes use the same curl-based engine as HTTPS probes, providing a full 4-layer timing breakdown (DNS, TCP, TLS, TTFB) visible in the Timing Analysis modal. They require a valid Stigix Key to authenticate against the Cloudflare Worker.
Probe configurations are stored in config/connectivity-config.json. Export the file using the Export button in the top-right toolbar of the Active Monitoring Probes section, or copy it directly from the config volume.
To import on a new instance: click the Import button (also in the top-right toolbar, next to Export) and upload the JSON file. The backend picks it up immediately — no restart needed.
For multisite PoCs, keeping a library of probe config files (one per customer vertical — retail, hospital, manufacturing) makes it trivial to load the right set of probes before a demo.
The top banner of the Digital Experience view contains three key sections:
Below the banner, Performance Trends by Type shows one mini-chart per probe protocol (HTTP/HTTPS, PING, DNS, UDP, STIGIX CLOUD). Each card displays the aggregate score, average latency, and success rate for that protocol family — useful to identify whether a degradation is protocol-specific (e.g. only UDP/voice paths are affected) or global.
The main Active Monitoring Probes table lists every probe with its last score, sparkline history, average latency range, and a reliability badge (percentage of successful polls). Click any probe row to open its detailed modal with timing breakdown and recent captures.
HTTP, HTTPS, and STIGIX CLOUD probes use curl to decompose each request into four distinct timing phases, shown as a stacked area chart in the Probe Performance modal:
Total latency = DNS + TCP + TLS + TTFB Example (Google Search, healthy path): DNS 7.7ms TCP 4.5ms TLS 24ms TTFB 35ms → Total 76ms
The Score Trend sub-chart within the probe modal shows score (solid line) and total latency (dashed orange line) on the same axis, making it easy to correlate score drops with latency spikes. The Recent Captures table gives the raw numbers for every poll cycle, including the IP address served — which changes when Anycast CDN load-balances or when a failover switches the egress PoP.
Prisma SD-WAN probes are a special probe category automatically discovered from the Prisma SD-WAN / Strata Cloud Manager API. Unlike custom probes that you create manually, these are synthesised directly from Prisma's own Application Probe Kit (APK) monitoring data — meaning the probe endpoints and types mirror what your SD-WAN already measures natively.
How auto-discovery works:
PRISMA_SDWAN_CLIENT_ID / CLIENT_SECRET / TSGID) to pull the list of monitored application probes from all branch sites.source: "discovery" and displayed with a shield icon badge in the probe table, distinguishing it from user-created probes.Filtering Prisma SD-WAN probes: In the Digital Experience tab, use the PRISMA SDWAN filter button in the top toolbar to isolate only auto-discovered probes. This is useful in multi-site deployments where you have dozens of probes and want to focus on the Prisma-native view.
Stale badge: If the Prisma API has not returned updated data for a probe within the expected refresh window, the badge turns orange and displays STALE — signalling that the API sync may have a problem (expired token, region mismatch, or network issue between Stigix and the Prisma cloud).
Requirements: Prisma SD-WAN probe discovery requires valid API credentials and the Prisma SASE API feature to be enabled in Settings → Prisma SASE API. The API uses OAuth2 client credentials — refer to the Settings & API FAQ for the exact setup steps.
Content matching is an optional feature for HTTP and HTTPS probes that verifies the response body contains (or does not contain) a specific text string. It is disabled by default — all existing probes continue to work exactly as before unless you explicitly enable it.
How to configure it:
contains — probe succeeds only if the response body includes the expected text.not_contains — probe succeeds only if the expected text is absent from the body (useful to detect error pages, maintenance banners, or deprecated API responses).How it works under the hood: After the normal HTTP request (which measures DNS/TCP/TLS/TTFB), a second bounded request fetches the body (capped at 10 KB, 3 s timeout). The normal timing metrics are never affected — they come from the first curl call. The body fetch only adds ~50–200 ms per polling cycle, only for probes where it is enabled.
Result fields added to each probe capture:
content_match_enabled true / false
content_match_mode contains | not_contains
content_match_value expected text (truncated to 80 chars in logs)
content_match_result "matched" | "text not found" | "text unexpectedly found"
| "body empty" | "fetch error"
content_match_ok true | false
When content_match_ok is false, the probe score is forced to 0 and the status becomes unreachable — it will appear in the Flaky / Down panels and the Match column in Recent Captures will show ✗ with the failure reason.
Backward compatibility: Probes without a content_match block behave exactly as today — the feature is completely opt-in. Existing JSON configs and API responses are not changed.
Typical use cases:
"Welcome" instead of a redirect to a login page."healthy" or "ok".not_contains on "Under maintenance".Four distinct policy enforcement areas:
urlfiltering.paloaltonetworks.com/test-malware-domains). A blocked response (redirect to block page, HTTP 403, or connection reset) = policy working.dig. NXDOMAIN or a sinkhole IP = policy working. Live resolution = bypassed.Security tests are driven by a vendor-agnostic profile JSON (config/security-profile.json). You can swap the entire test set by loading a different profile, each targeting the correct test infrastructure for that vendor.
Three ways to switch profiles:
POST /api/security/profile with a JWT and the JSON bodyconfig/security-profile.json; read on every request, no restart neededExample Fortinet profile structure:
{ "vendor": "fortinet",
"url_filtering": { "items": [
{ "id": "malicious", "name": "Malicious",
"url": "https://www.eicar.org/download/eicar.com.txt" }
]},
"dns_security": { "items": [
{ "id": "botnet", "name": "Botnet C2",
"domain": "botnet.test.fortiguard.com", "category": "basic" }
]}
}
The most common causes in order of frequency:
Each test type (URL, DNS, Threat, C2, AI) has its own independent scheduler. When enabled, tests run automatically in the background after the configured interval — no need to click "Run All".
Recommended intervals by use case:
The scheduler persists across container restarts. Results accumulate in logs/test-results.jsonl and are displayed in the results table with timestamps.
Yes. Every URL, DNS, and EICAR target row has an individual Play ▶ button that runs just that single test in isolation — without affecting other targets or the scheduler. This is useful for:
There is also a Copy 📋 button on each EICAR target row that copies the equivalent curl command so you can run the test manually from any terminal.
EDL (External Dynamic List) testing lets you validate that your firewall or SD-WAN gateway correctly blocks traffic matching bulk threat intelligence lists — IPs, URLs, and domains — at scale, without manually crafting individual test cases.
Three list types supported:
ping toward the target IP. A blocked response (timeout or ICMP unreachable from the firewall) = policy working.curl. A redirect to a block page or HTTP 403 = URL filtering enforced.nslookup / dig. An NXDOMAIN or sinkhole IP response = DNS Security enforced.Loading your lists:
.txt or .csv file with one entry per line.Test modes:
A Max Elements / Run cap prevents overloading the firewall or saturating the network during bulk tests. Each element test has a strict timeout (2–10s depending on type).
Results: A mini summary table shows the last 5 results inline per list type. Full results (pass/fail per entry, latency, timestamp) are stored in the Test Results history tab and are queryable via the CLI or MCP Server.
Stigix uses XFR (eXpress Flow Reporter) as its bandwidth testing engine instead of the commonly used iperf3. This was a deliberate choice driven by three key limitations of iperf3 in SD-WAN validation contexts:
The result is a speedtest that feels more like a live network monitoring tool: you see the throughput curve evolve in real time, can spot congestion spikes as they happen, and can immediately cross-reference the traffic in your SD-WAN analytics portal using the pinned source port.
XFR is open-source: github.com/lance0/xfr
The XFR test panel in Stigix exposes the full engine capability set:
Protocols:
Directions:
Advanced options:
0 to detect peak throughputXFR_MAX_DURATION)🔑 Deterministic source port — automatic flow traceability:
For UDP and QUIC tests, Stigix automatically derives a deterministic source port from the test sequence number so every run is identifiable in SD-WAN flow logs without any manual configuration:
XFR-0007 (UDP/QUIC) → source port 40007 (range 40000–49999) XFR-0123 (UDP/QUIC) → source port 40123
For TCP tests the source port is ephemeral by default — use the Client Flow Port field to pin it manually if you want to track a TCP speedtest in Prisma flow logs. For UDP/QUIC you can also override the auto-derived port by setting a custom Client Flow Port.
Tests can be launched from the Speedtest tab in the dashboard, via the CLI (speedtest start --target <name>), or via the MCP Server ("Run a 30-second TCP speedtest between BR8 and DC1").
As soon as the test starts, Stigix connects to the XFR JSON stream endpoint (/api/tests/xfr/:id/stream) and renders a live graph. The metrics displayed depend on the protocol:
TCP tests:
UDP / QUIC tests:
All data is streamed in real time — there is no waiting until the end of the test to see results. When the test completes, the final summary (total bytes transferred, average throughput, peak RTT, total retransmits) is stored in the history and is queryable via CLI or MCP.
XFR uses a dedicated port separate from the Stigix management port. The default configuration:
9000 TCP/UDP (configurable via XFR_PORT in .env or docker-compose)9000 from the source node's IPFirewall checklist:
TCP 9000 and UDP 9000 from all Stigix source IPsTCP/UDP 9000 (usually open by default)Rate limiting and abuse protection: The server side enforces hard limits via environment variables:
XFR_MAX_DURATION — maximum test duration in seconds the server will accept (default: 3600). The server severs the connection if the client requests longer.XFR_RATE_LIMIT — max number of concurrent active tests (default: 2). Additional requests are queued.XFR_ALLOW_CIDR — IP whitelist for incoming test connections (default: 0.0.0.0/0 = all). Restrict to your lab CIDR for tighter security.The IoT engine uses Scapy to craft and inject raw network frames at Layer 2/3. It simulates full device lifecycle: DHCP discovery/request/ACK (with vendor-specific option 55 fingerprints), ARP announcements, and application-level traffic — making simulated devices indistinguishable from real hardware to the network.
This is important for Palo Alto IoT Security demos: the DHCP fingerprint triggers the classification engine, which correlates MAC OUI, DHCP option strings, and traffic patterns to identify device type and assign a trust score.
App traffic (the Traffic Generator) produces standard HTTP flows from the Stigix container itself. IoT Simulation creates distinct virtual MAC addresses for each simulated device, making each appear as a separate endpoint on the network. This enables:
Pre-built vertical examples are available for: healthcare, manufacturing, utilities/SCADA, retail, and smart office. These can be loaded directly without any LLM call.
No — the host OS matters significantly:
For maximum realism in a DHCP fingerprinting demo, a Linux host is required. A lightweight Alpine or Ubuntu VM on the same physical segment works well.
The Import button in the IoT Simulation toolbar offers three different import paths, each suited to a different situation:
🔒 Stigix JSON Config — Restores a full IoT simulation environment from a previously exported .json file.
📄 Device Security Assets — Imports devices from a Palo Alto IoT Security / Prisma Access inventory CSV (one row per device).
display_apps / Applications column for realistic protocol mix, and applies ml_risk_level (Critical/High) to automatically enable bad behavior on risky devices.profile_vertical == IoT, excludes PCs/VMs/tablets), Security percentage (force bad behavior on a fixed % of devices).How to export from Prisma Access:
Key CSV columns used: hostname, mac address, profile, profile_vertical, ml_risk_level, display_apps, vendor. The output uses real MAC addresses from the CSV, so PAN IoT Security will recognise the same DHCP fingerprints it originally classified.
⚠️ Vulnerability Report — Imports from a Palo Alto CVE/Vulnerability export (one row per CVE per device) — the richest threat intelligence source.
How to export from Prisma Access:
Key CSV columns used: Device Name, MAC Address, CVE, CVSS, Severity, ICS-Cert, APT Names, Risk Score, Site Name, OS.
Danger Score = Risk Score (0-100)
+ Critical CVEs × 15 + High CVEs × 8 + Medium CVEs × 3
+ APT Groups × 5 + ICS-CERT × 10 + Max CVSS × 2
Threat-aware bad behavior (Auto mode): APT groups → beacon | ICS-CERT → port_scan | Critical/High CVEs → pan_test_domains
You can also override Auto mode with: All devices, Percentage (random N%), or None (import clean, no attack simulation).
Which export to use? Use Device Inventory for a broad realistic device population. Use Vulnerability Report for executive-level security demos that show specific CVEs, APT attribution, and risk scoring — far more impactful.
When Bad Behavior is enabled on a device, it generates traffic matching known attack profiles — designed to be detected by Palo Alto IoT Security, DNS Security, and URL Filtering. Multiple behaviors can run simultaneously as parallel threads on the same device.
Available attack patterns:
pan_test_domains) — 2 DNS queries to official Palo Alto test domains + 1 HTTPS/HTTP SYN, every 90s. Guaranteed detection by PAN-OS — ideal for policy validation demos.beacon) — 1 DNS + 1 TCP SYN to a fake Command & Control domain, every 45s. Simulates realistic APT heartbeat traffic.dns_flood) — Burst of 3 DNS queries to suspicious domains, every 60s. Simulates compromised device calling home repeatedly.port_scan) — TCP SYN to 10 common ports on a random target, every 120s. Simulates OT lateral movement (common in ICS-CERT scenarios).data_exfil) — 2 large TCP uploads (1400-byte payloads) to external IPs, every 90s. Simulates bulk data theft.random) — Picks one of the above at random per cycle (every 20–60s). Useful for background noise simulation.All attack traffic is generated using Scapy raw sockets (Layer 2/3), so it appears as genuine network traffic to firewalls, NGFW flow analyzers, and IoT Security classifiers — not as application-layer HTTP from the container itself.
The intervals were tuned to avoid Python D-state accumulation under concurrent device load while still producing detectable attack patterns. You can combine multiple behaviors on the same device (e.g. ["beacon", "port_scan"]) to simulate a fully compromised APT device.
Each simulated IoT device runs via Scapy raw sockets inside a single Python process. Running too many concurrently causes threads to enter Python D-state (uninterruptible I/O wait), which starves the CPU scheduler and breaks latency-sensitive services like VoIP:
163 devices active: CPU ~100%, 5+ D-state threads, VoIP loss 37-73% ❌ 30 devices active: CPU ~18%, 0 D-state threads, VoIP loss 0% ✅
Stigix uses a semaphore queue: only maxConcurrentDevices devices run Scapy at any time. The rest rotate through a queue. Each device has four states:
traffic_interval seconds before re-queuingTuning from the UI: The IoT Concurrency Control slider at the top of the IoT tab lets you set the limit live — no restart needed. Raising it promotes QUEUED devices to ACTIVE immediately; lowering it lets ACTIVE devices finish their current cycle gracefully before releasing slots.
The System Health mini-panel shows CPU%, UDP errors/s, and Python D-state count in real time. When D-state ≥ 3 or CPU > 80%, lower the concurrency slider to protect VoIP simulation quality.
The default (30 devices) is a good starting point for most lab machines. On a Raspberry Pi 5 (4 GB RAM), 20–25 is safer. On a server-class Intel NUC or VM with 4+ vCPUs, 40–50 is usually fine.
The traffic_interval field controls the full duty cycle of a device. It sets both how long the device is ACTIVE (sending Scapy traffic) and how long it is IDLE (sleeping) between cycles:
Phase Duration What happens ACTIVE traffic_interval (s) Scapy runs: DHCP, ARP, protocols, bad behavior IDLE traffic_interval (s) Device sleeps — no packets sent Full cycle 2 × traffic_interval Before the device can run again
Example with interval = 180s: the device is active for 3 minutes, then idle for 3 minutes (total 6-minute cycle). This is deliberately realistic — real IoT devices (cameras, sensors, HVAC) operate in bursts then sleep, not continuously.
Queue wait time with many devices:
Avg cycle ≈ 2 × 180s = 360s Slot rate = 30 slots / 360s ≈ 1 slot every 12s Queue wait ≈ (N − 30) × 12s (e.g. 100 devices → 14 min)
The interval is set per-device in the Edit modal, in the JSON (traffic_interval field), or assigned randomly between 60–300s at import time. A value of 60s gives high-frequency traffic; 300s gives sparse, realistic background traffic.
Yes — by default, simulated devices reclaim the same IP after a container restart. Stigix implements RFC 2131 INIT-REBOOT: when a device wakes up, it sends a single DHCP REQUEST for its last known IP (stored in config/dhcp_leases.json) instead of starting a full Discover cycle:
First boot: DISCOVER → OFFER → REQUEST → ACK (full cycle, ~4s)
Restart: REQUEST (INIT-REBOOT, requested_addr = last IP) → ACK (<1s)
— no DISCOVER, no OFFER needed
The lease file maps each MAC to its last IP and gateway. It lives in the persistent Docker volume (./config/), so it survives container restarts and image upgrades.
Fallback scenarios:
This is exactly how real IoT devices behave when waking from sleep. It also means your SD-WAN policy and IoT Security visibility rules don't need to be re-applied after a lab restart — the same IP/MAC pair reappears immediately.
The Python generator (generate_iot_devices.py) includes 13 device categories, 50+ vendors, and 200+ device models with pre-built realistic DHCP fingerprints. It runs offline in under 1 second and requires no API key.
Device categories:
Supported protocols per device: dhcp, arp, lldp, http, https, rtsp (cameras), cloud (heartbeat to vendor FQDN), mqtt (telemetry), dns, ntp, modbus (SCADA), bacnet (building automation).
Pre-built presets:
python iot/generate_iot_devices.py --preset small # 30 devices python iot/generate_iot_devices.py --preset medium # 65 devices python iot/generate_iot_devices.py --preset large # 110 devices python iot/generate_iot_devices.py --preset enterprise # 170 devices # Custom mix for a hospital scenario: python iot/generate_iot_devices.py --custom "Medical Devices:15,Security Cameras:10,HVAC:5"
For industry-specific device mixes with customer context (realistic names, descriptions, narratives), use the LLM-based generation method instead — pre-built vertical examples are available for healthcare, manufacturing, utilities/SCADA, retail, and smart office.
Voice Testing generates bidirectional RTP-style UDP streams between the Stigix instance and a configured target (usually another Stigix node or any iperf3 server). It measures:
Results are shown per call session and plotted over time in the Voice dashboard.
🔑 Deterministic source port — built-in flow traceability: Each RTP call uses a source port derived from its internal CALL-ID. This is embedded in the UDP payload and mapped deterministically:
CALL-0001 → UDP source port 31001 CALL-0015 → UDP source port 31015 (range 31000–31999)
This means you can filter your SD-WAN Orchestrator or Prisma SD-WAN flow browser by src-port 31015 to instantly isolate which tunnels and circuits a specific call traversed. The CALL-ID is also embedded in the RTP payload itself, so the echo server on the remote side can decode and log which call it is echoing back.
Basic failover observation (e.g. watching ping stop and resume) tells you that a failover happened. The Convergence Lab tells you how bad it was:
Each test receives a unique ID (e.g. CONV-0042) and is logged to logs/convergence-history.jsonl for audit and comparison. If Prisma SD-WAN API credentials are configured, the active egress path (e.g. BR8-INET2 → DC2-INET) is automatically enriched 60 seconds after the test completes.
🔑 Deterministic source port — exact flow correlation: Each convergence probe uses a UDP source port derived from its test number. The sequence number and a high-resolution timestamp are embedded in the UDP payload itself:
CONV-0001 → UDP source port 30001 CONV-0042 → UDP source port 30042 (range 30000–39999)
You can filter your SD-WAN Orchestrator flow browser by udp src-port 30042 to see exactly which WAN tunnel carried each probe packet during the failover window. This makes it possible to prove, with flow-level evidence, which circuit was active when the blackout occurred.
For maximum impact, combine both: run a voice session continuously, trigger a failover (manually or via VyOS impairment), and show how the Convergence Lab captures the exact outage window that correlates with the MOS dip in the Voice dashboard.
VyOS Control is a subsystem that automates network-level impairment injection on VyOS routers via the VyOS HTTP API. It allows you to programmatically simulate real-world network degradation scenarios without touching router configs manually.
Capabilities:
SEQ-xxxx or MAN-xxxx), timestamp, duration, and parametersRequirements:
Minimal VyOS configuration:
set service https api keys id MY-KEY key 'YOUR-API-KEY-HERE' set service https api-restrict virtual-host vyos.lab commit save
Then add the router in VyOS Control → Routers → Add Router with the management IP and API key. Stigix will automatically discover all interfaces and their descriptions (e.g. "Paris to NYC MPLS"), which are promoted throughout the UI for easy identification.
Go to VyOS Control → Sequences → New Sequence. A sequence is a list of timestamped actions:
T+0 min → SET-QOS eth1 latency=50ms loss=0% (degradation starts) T+5 min → SET-QOS eth1 latency=200ms loss=5% (brownout) T+10 min → CLEAR-QOS eth1 (recovery) T+15 min → SET-QOS eth0 latency=30ms loss=2% (failover path now degraded) T+20 min → CLEAR-QOS eth0 (full recovery)
Key rules:
SEQ-0042 for automatic cyclic runs, MAN-0007 for manual triggers. This allows you to correlate impairment events with convergence test results and voice MOS dips.This error means the vyos-http-api service has entered an unstable state — usually after a period of uptime or a partial configuration change. The config on the router is fine; the API daemon needs a restart.
Resolution steps:
# 1. Verify the API config is still correct show configuration commands | match 'service https' # 2. Restart the HTTP-API service (fastest fix) sudo systemctl restart vyos-http-api.service # 3. Verify it came back up show log | match 'vyos-http-api' # Expected: "Configuration success" + "Serving on http://localhost:8080"
If the API config itself has stale entries (e.g. an old key ID), clean them up in configuration mode before restarting:
configure delete service https api keys id OLD-KEY-ID commit save exit
Yes. When the Stigix MCP Server is configured with Claude Desktop, you can issue plain-English commands like:
The MCP server translates these into the VyOS API sequence lifecycle automatically: creates a temporary ad-hoc sequence, executes it immediately (MAN-xxxx run ID), retrieves the CLI equivalent for confirmation, and cleans up the temp sequence. See MCP_SERVER.md for setup instructions.
Step 1 — Create a Service Account in Strata Cloud Manager:
prisma-sdwan-config.read and prisma-sdwan-monitor.readStep 2 — Add to your .env or docker-compose.yml:
PRISMA_SDWAN_CLIENT_ID="[email protected]" PRISMA_SDWAN_CLIENT_SECRET="your-client-secret" PRISMA_SDWAN_TSG_ID="1234567890" # Optional PRISMA_SDWAN_REGION="de" # de, us, uk, etc. PRISMA_SDWAN_CACHE_TTL=600 # Cache in seconds (default 10 min) DEBUG=true # Verbose API logs in docker compose logs
Features unlocked once configured:
BR8-INET2 → DC2-INET)Key environment variables for the all-in-one container:
JWT_SECRET="change-me-in-production" # Auth token secret (required) ADMIN_PASSWORD="your-password" # Dashboard login password PORT=8080 # Web UI port (default 8080) # Stigix Cloud / Registry STIGIX_TARGET_BASE_URL=https://... # Override Cloud Worker URL STIGIX_TARGET_MASTER_KEY="..." # Key for advanced Cloud Worker features STIGIX_TARGET_SHARED_KEY="..." # Signing key for authenticated Cloud probes # Network NETWORK_INTERFACE=eth0 # Interface for traffic generation
All variables can be set in .env at the project root or directly in docker-compose.yml under the environment: section. Changes take effect after container restart.
Stigix Targets are remote endpoints that host the Stigix agent services (voice, convergence, XFR, security, connectivity). Add them in Settings → Stigix Targets using the Add Stigix Target button:
Targets can also be auto-discovered via the Stigix Registry (Hybrid Registry feature) — remote agents register themselves automatically, and the dashboard shows them as "Discovered" with their last-seen timestamp. This simplifies multi-site deployments significantly.
The backend exposes a full REST API on the same port as the UI (default 8080). All protected endpoints require a JWT token.
Authenticate:
curl -X POST http://<HOST>:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"password": "your-password"}'
# Returns: { "token": "eyJ..." }
Common API calls:
# Get current status curl http://<HOST>:8080/api/status \ -H "Authorization: Bearer <TOKEN>" # Run all enabled security tests curl -X POST http://<HOST>:8080/api/security/run \ -H "Authorization: Bearer <TOKEN>" # Import a security profile curl -X POST http://<HOST>:8080/api/security/profile \ -H "Authorization: Bearer <TOKEN>" \ -H "Content-Type: application/json" \ -d @my-profile.json
Full API reference is available in docs/API_REFERENCE.md. The Stigix CLI wraps all common API calls for convenience.
The MCP (Model Context Protocol) server lets Claude Desktop control Stigix via natural language. Setup in claude_desktop_config.json:
{
"mcpServers": {
"stigix": {
"command": "python3",
"args": ["/path/to/stigix/mcp-server/src/server.py"],
"env": {
"STIGIX_URL": "http://<HOST>:8080",
"STIGIX_TOKEN": "your-jwt-token"
}
}
}
}
Once configured, you can control Stigix entirely from Claude Desktop: run security tests, trigger VyOS impairments, query probe status, manage traffic profiles, and more — all in plain English. See MCP_SERVER.md for the full tool catalog.
⚠️ Beta feature — under active development. The Topology view is already useful but will gain new capabilities in upcoming releases.
The Topology tab provides a live visual map of your Prisma SD-WAN fabric directly in the Stigix dashboard — without having to navigate the Prisma Orchestrator UI. It shows:
ACTIVE (routing traffic), BACKUP (usable but idle), or DOWN (link failure)DC1-R1)This is particularly powerful during failover demos: as you trigger a VyOS impairment or physically disconnect a link, the Topology view updates in real time to reflect which tunnels went DOWN and which BACKUP path became ACTIVE.
Current scope: The Topology view currently covers Prisma SD-WAN only (ION devices, VPN links, WAN circuits). A Prisma Access / ZTNA overlay is not yet implemented.
The Topology view queries the Prisma SD-WAN API directly. It requires Prisma SD-WAN service account credentials:
PRISMA_SDWAN_CLIENT_ID — your service account Client IDPRISMA_SDWAN_CLIENT_SECRET — the corresponding secretPRISMA_SDWAN_TSGID — your Tenant Service Group ID (TSG ID)PRISMA_SDWAN_REGION — your tenant region (e.g. Germany, US)The easiest way to enter credentials is via the UI — no file editing needed:
Once credentials are saved, the Topology tab becomes active and data is fetched automatically. The system also uses these credentials for Flow Search (getflow), Convergence path enrichment, and Cloud Autodiscovery.
Important: These are Prisma SD-WAN credentials (service account from the Prisma SD-WAN Orchestrator). A regular Prisma Access admin account will not work — the API uses OAuth2 client credentials with SD-WAN-specific scopes.
Currently supported (SD-WAN):
Not yet supported / in development:
If you have a feature request or encounter a bug, open a GitHub Issue or contact [email protected].
The all-in-one image (jsuzanne/stigix:latest) is the recommended default. It bundles the web UI, backend API, traffic generator, and all engines into a single container.
docker run -d \ --name stigix \ --network host \ -v stigix_config:/app/config \ -v stigix_logs:/app/logs \ --env-file .env \ jsuzanne/stigix:latest
Legacy separate images (traffic-gen, web-dashboard, voice-server) remain available for advanced scenarios where you need to run components on different hosts. The docker-compose.yml at the project root covers both modes.
# 1. Is the container running? docker ps | grep stigix # 2. Check container logs for startup errors docker logs stigix --tail=50 # 3. Is port 8080 bound? ss -tlnp | grep 8080 # Linux netstat -an | grep 8080 # macOS # 4. Check for port conflict # If another service is on 8080, change via PORT env var or -p flag
Common causes: Docker daemon not running, port 8080 already in use by another service, firewall blocking inbound connections, or a startup crash visible in docker logs.
Your configuration and logs are always preserved — they live in Docker named volumes that are never touched by an upgrade.
Method 1 — Simple (works on all Docker versions):
docker pull jsuzanne/stigix:stable docker compose down docker compose up -d
Pull the new image, stop the container, start fresh. Safe and universal — works with every Docker version including older ones.
Method 2 — Force-recreate (recommended after several upgrades):
docker compose down docker pull jsuzanne/stigix:stable docker compose up -d --force-recreate
The --force-recreate flag creates a brand new container even if nothing in the compose file changed. Useful when the container appears stale or behaves unexpectedly after an update.
Method 3 — One-liner (modern Docker only — Compose v2, Engine 23+):
docker compose up -d --pull always --force-recreate
Note: --pull always is only available in recent Docker versions. If you see an unknown flag error, fall back to Method 1 — it is fully equivalent and works everywhere.
docker-compose vs docker compose: Older systems may only have the legacy docker-compose binary (with a hyphen). Replace docker compose with docker-compose in any command if needed:
# Check which you have docker compose version # Compose v2 (built into Docker Engine) docker-compose version # Compose v1 (legacy separate binary)
After upgrading, confirm the new version in Settings → System Info or via the CLI: docker exec -it stigix stigix-cli --exec "status"
Every time you pull a new image, Docker keeps old image layers on disk unless you explicitly remove them. After several upgrades this commonly reaches 2–5 GB of wasted space.
First, check how much Docker is using:
docker system df
This shows image size, container size, volume size, and build cache. The Images and Build Cache rows grow with every upgrade.
Remove unused images only (safe, run regularly):
docker image prune -a
This removes all images not currently used by a running container. Your active Stigix image is kept, old versions are removed.
Full cleanup — removes everything unused (images, stopped containers, networks, build cache):
docker system prune -a -f
Important: docker system prune -a -f does not remove named volumes by default. Your Stigix configuration (stigix_config) and logs (stigix_logs) are stored in named volumes and are completely safe. Only unused images and stopped containers are deleted.
After pruning, simply restart Stigix:
docker pull jsuzanne/stigix:stable docker compose up -d
When to clean up:
docker system df shows more than 2 GB in imagesdocker system prune -a -f immediately before your next upgradeJWT_SECRET to a 32+ character random stringADMIN_PASSWORD in .env--memory and --cpus limits on the container to prevent resource exhaustionstigix_config volume before updateslogs/traffic.log → Live traffic generator requests (one per line) logs/stats.json → Aggregated per-app request distribution logs/test-results.jsonl → Security test history (one JSON object per run) logs/voice-stats.jsonl → Voice session results (MOS, jitter, loss) logs/convergence-history.jsonl → Convergence test records + egress path logs/vyos-history.jsonl → VyOS impairment execution audit trail config/applications-config.json → Traffic generator profile config/security-profile.json → Security test profile (multivendor) config/connectivity-config.json → Probe definitions config/vyos-sequences.json → VyOS impairment sequences
All log files are in newline-delimited JSON format (JSONL), making them easy to parse with jq, import into Elastic/Splunk, or analyze with Python/pandas.
stigix-cli is an interactive console and automation tool that connects to the Stigix backend API. It lets you trigger tests, view real-time stats, run security audits, control IoT devices, manage VyOS sequences, and monitor convergence — all from the terminal without touching the UI.
It is pre-installed inside the container. Launch it with:
# Interactive console (with autocomplete, history, status toolbar) docker exec -it stigix stigix-cli # Run a single command headless and exit docker exec -it stigix stigix-cli --exec "status" # Connect to a remote Stigix instance docker exec -it stigix stigix-cli --url http://192.168.1.100:8080 # Execute a script file (one command per line) docker exec -it stigix stigix-cli --script my-test-plan.txt
The interactive console supports F1 (help), F5 (refresh toolbar), Ctrl+L (clear screen), and tab autocomplete. Session tokens are saved in ~/.stigix-cli.json for seamless reconnection.
Traffic generator (traffic):
traffic start / stop / status traffic speed [turbo|fast|normal|slow|0.5] # set request rate traffic density [1-20] # parallel workers traffic stats # real-time counters traffic export [file] # backup profile to JSON traffic import <file> # restore profile from JSON
Security audits (security):
security suite # full automated audit (URL + DNS + Threat) security url <url> # single URL test security url-batch # all enabled URL categories security dns <domain> # single DNS test security dns-batch # all enabled DNS domains security eicar [endpoint] # EICAR threat prevention test security results [n] # last N results security schedule url on 30 # schedule URL tests every 30 min security select-all url on # enable all URL categories at once
Convergence & failover (convergence):
convergence start --target 192.168.203.100 --pps 1000 --label DC1 convergence stop convergence watch # real-time loss + latency display convergence history [n] # past test results with blackout times
Bandwidth speedtest (speedtest):
speedtest run 192.168.203.100 # default TCP test speedtest run 192.168.203.100 --duration 30 --protocol udp # custom test speedtest run 192.168.203.100 --direction bidirectional # bidir speedtest history # past results
Speedtest streams real-time Tx/Rx throughput, RTT, and loss directly in the console as the test runs.
VoIP simulation (voice):
voice start # interactive: choose target from list voice start --target all # start to all voice-capable nodes voice stop voice stats # MOS, jitter, packet loss, RTT
DEM Probes (probes):
probes list probes add --name HQ-GW --host 10.0.0.1 --type ping probes remove <id> probes stats # global scores + latency averages probes export / import # backup and restore probe configs
Stigix Targets (target):
target list # all nodes with capabilities and status target add # interactive (prompts name + host) target add --name DC1 --host 192.168.203.100 target enable / disable <name> target export / import # portable JSON backup
IoT Simulation (iot):
iot list iot start / stop [device-id] # one device or all iot stats # packets sent, bandwidth iot vulns [n] # CVE findings per device iot import <file> --max-devices 20 --enable-security # Prisma CSV or JSON iot export
VyOS Control (vyos):
vyos list # connected routers vyos sequences # available sequences vyos run <sequence-id> # trigger a sequence vyos stop <sequence-id> vyos history [n] vyos export / import # router + sequence config backup
Prisma SD-WAN Flow Browser (flows): Requires Prisma API credentials configured in your .env.
flows query --site BR8 flows query --site BR8 --protocol tcp --dst-port 8082 --dst-ip 192.168.203.100 --minutes 15
Returns matching flows with source/destination, protocol, bytes, packet counts, and the SD-WAN path used (e.g. BR8-INET1 to DC1-INET).
System administration (system):
system info # CPU, RAM, disk, uptime system interfaces # host network interfaces system logs # last 30 lines of backend logs system restart # restart the container services system upgrade # pull latest image and upgrade
Automation with script files: The CLI can run a plain text file with one command per line, making it easy to build repeatable test plans:
# test-plan.txt auth login traffic start security suite convergence start --target 192.168.203.100 --pps 500 --label PoC voice start --target all
docker exec -it stigix stigix-cli --script test-plan.txt
The Stigix MCP Server provides a natural language interface to your entire SD-WAN validation mesh. Using Claude Desktop, you can manage traffic, run security audits, trigger speedtests, inject network impairments on VyOS, and monitor any node — all by typing plain English (or French).
The MCP server runs automatically on every Stigix instance on port 3100 — no extra setup needed. To connect Claude Desktop, add this to your claude_desktop_config.json (replace with your node IP):
{
"mcpServers": {
"stigix": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/inspector",
"http://<STIGIX_NODE_IP>:3100/sse"]
}
}
}
Config file locations: macOS → ~/Library/Application Support/Claude/claude_desktop_config.json Windows → %APPDATA%\Claude\claude_desktop_config.json
After saving, fully restart Claude Desktop (Cmd+Q, reopen). Click the hammer icon — you should see Stigix with a green status and 53 tools available.
No Node.js? Use the Python bridge instead: clone the repo, run ./mcp-server/setup-bridge.sh, then point the config to the local Python bridge script. See MCP_SERVER.md for the full setup.
🔔 Claude Pro recommended: Stigix MCP sessions are tool-heavy — a single fabric-wide report or full security audit can invoke 10–20 tools and return thousands of tokens of data. The Claude free tier hits its usage limit very quickly under this load and will stop mid-session asking you to wait until the next usage window. A Claude Pro (or Teams / Enterprise) subscription is strongly recommended for a smooth, uninterrupted experience.
Just type naturally — Claude resolves your intent to the right API call automatically. Here are real prompts you can copy-paste into Claude Desktop:
Discovery & Status:
"Show me all available Stigix endpoints." "Give me the full status of BR8." "Generate a full report across all Stigix nodes." "Compare BR8 and Hetzner side by side."
Traffic & Tests:
"Start application traffic generation on BR8." "Set 10 parallel clients on Paris." "Run a 30-second TCP speedtest between BR8 and DC1." "Start a convergence test between BR8 and DC1 at 500 pps." "Start voice simulation on BR8." "What is the success rate of Teams on BR8?"
Security:
"What is the current security score for BR8?" "Run a full security audit on BR8." "Test URL filtering for the Hacking category on BR8." "Run a DNS security test for the malware domain on BR8." "Run an EICAR threat prevention test against DC1 from BR8."
DEM Probes:
"Give me the DEM summary for BR8." "Trigger an immediate run of all DEM probes on BR8." "Add a PING probe to 8.8.8.8 named Google-Test on BR8." "Show me historical DEM stats for BR8 over the last hour."
Config Cloning:
"Clone the full configuration from BR8 to BR5: apps, probes, security profile, and VyOS scenarios." "Copy only the DEM probes from BR8 to BR5." "Export BR8's app config, then import it to Paris."
This is one of the most powerful MCP features. Claude can inject latency, loss, rate-limits, and IP blocks on VyOS routers using natural language — with a mandatory confirmation step before any destructive action.
Example prompts:
"Add 150ms of latency on the MPLS link of BR8." "Add 5% packet loss on the WAN interface of the router on BR8." "Block traffic to 192.168.1.50 on the router managed by BR8." "Shut the MPLS interface on BR8's router." "Clear all active QoS on the router managed by BR8." "Do a full reset of BR8's router — QoS, IP blocks, and downed interfaces." "What is the current state of the router managed by BR8?"
How it works: Claude first calls get_vyos_interfaces to discover the router interfaces and their descriptions (e.g. BR1-MPLS-197). It then resolves your intent to the right interface, presents the proposed action with the exact interface name, and waits for your yes/no confirmation before executing. Destructive actions (shut, block, deny) are never applied without explicit user confirmation.
Prerequisite: VyOS interface descriptions must be set for natural language resolution to work. Example: set interfaces ethernet eth1 description "MPLS-Link-DC1"
You can also check the live router state anytime:
"What is the current state of vyosrouter managed by BR8?"
Returns: per-interface admin status (up/down), active QoS parameters (delay, loss, rate), and all active IP blocks — in a single call.
You only need to connect Claude Desktop to one node. Thanks to the distributed architecture, that node automatically has visibility over the entire mesh via the autodiscovery registry — and can orchestrate any other node from there.
However, for cross-node operations (e.g. launching a speedtest from BR5 via the MCP connected to BR8), all nodes must share the same JWT_SECRET. The install script generates a unique random secret per node, so in a multi-node setup you need to manually synchronize it:
# Check current secret on each node docker exec stigix printenv JWT_SECRET # Set the same shared secret on every node echo "JWT_SECRET=<your-shared-secret>" >> ~/stigix/.env docker compose restart
If cross-node tests return empty results (tests: []), a mismatched JWT_SECRET is almost always the cause. Verifying this is the first debug step.
After upgrading Stigix (container restart), Claude Desktop loses the SSE connection. Simply quit and reopen Claude Desktop — the connection re-establishes automatically. You do not need to change claude_desktop_config.json.
No. Stigix never sees your natural language prompts. The translation happens entirely on Anthropic's servers:
You type: "What is the security score for BR8?"
↓ sent to Anthropic (Claude LLM)
Claude reasons → selects tool + arguments
↓ structured JSON-RPC call
{"name": "get_security_results_stats", "arguments": {"agent_id": "BR8"}}
↓ SSE → port 3100
Stigix MCP Server receives only the structured call
Stigix logs only the tool call metadata to mcp-history.jsonl: tool name, target node, duration in ms, and status. Your conversational text is never logged by Stigix.
This means:
Settings → MCP Server shows a real-time color-coded feed of every tool call with category icon, duration bar, node badge, and timestampIn a multi-node Stigix deployment, every node needs to know the IP address of every other node to run speedtests, convergence tests, and voice sessions. Without a registry, you would have to manually enter the IP of every peer in every node's Settings — and repeat the process every time an IP changes.
The Stigix Registry solves this completely. It is a lightweight Cloudflare Worker running at registry.stigix.io that acts as a shared discovery board. Each Stigix instance:
Result: when a new Stigix node starts up, it finds all its peers within 30–90 seconds — with zero manual configuration. Peers appear in the dashboard with an Auto badge and a Registry Provided tooltip, distinguishing them from manually added targets.
The registry is also used by the MCP Server to maintain mesh-wide visibility — so Claude Desktop can see and control all nodes from any single entry point.
The Stigix Key (called Stigix Master Key in the UI) is a token that groups your nodes together in the shared Cloudflare registry and signs cloud probe requests so only your infrastructure can use them.
Step 1 — Request your key: Send an email to [email protected] with subject "Stigix Registry Key Request". Include your organization name and number of nodes. You'll receive a key value by return.
Step 2 — Enter it directly in the dashboard (no restart required):
The badge next to the field instantly shows + MASTER KEY ACTIVE. Repeat on every node in your deployment — all nodes must share the same key to recognize each other.
Already using Prisma SD-WAN? If PRISMA_SDWAN_TSGID + credentials are configured, the key is derived automatically from your TSG ID. No manual entry needed — nodes in the same Prisma tenant are automatically grouped.
Getting a node to register itself and discover its peers is a 2-step process — no command line needed after the initial install.
Step 1 — Enter your Stigix Key in the dashboard:
Go to Settings → Target Controller → Cloud Target Security. Paste the key you received from [email protected] into the Stigix Master Key field and click Update Security. The badge shows + MASTER KEY ACTIVE immediately — no restart needed.
No key yet? If you have Prisma SD-WAN credentials already configured, skip this step — the key is derived automatically from your TSG ID.
Step 2 — Verify registry status:
Go to Settings → Target Controller. The Configuration State panel should show:
https://registry.stigix.ioWithin 30–90 seconds, other nodes registered with the same key will appear in your Targets list with an Auto badge — no manual IP entry needed.
For large multi-site deployments, Stigix adds a Leader/Peer layer on top of the global registry. One node (typically the DC or a central hub) acts as a Leader — it hosts a local registry service and pushes a centralized target list to all other nodes (Peers). This gives you sub-minute synchronization without depending on Cloudflare for every heartbeat.
Step 1 — Designate the Leader node:
On your central/DC node, go to Settings → Target Controller. Under Registry Role Override, click Force Leader. No restart needed — the role switch is instant and the node immediately announces itself to the Cloudflare registry.
Step 2 — Add your shared targets on the Leader:
In Settings → Targets on the Leader node, add any custom targets you want all Peers to see (internal servers, specific probe endpoints, other Stigix nodes). These are the targets that will be propagated.
Step 3 — Leave Peers on Auto-Detect:
All other nodes should stay on the default Auto-Detect mode (or set STIGIX_REGISTRY_MODE=auto in .env). They will automatically discover the Leader via Cloudflare within 60–90 seconds and switch to the local Leader for high-frequency updates.
What happens automatically:
Step 1 — Check registration status:
curl -s http://localhost:8080/api/registry/status | python3 -m json.tool
Look for:
"is_registered": true — the node is registered with the global registry"poc_id" — should match your TSG ID (or your PoC identifier)"peer_count" — number of peers currently discoveredStep 2 — Test connectivity to the registry:
curl -I https://registry.stigix.io/instances
A 403 Forbidden is normal (authentication required). A 521 or timeout means the host cannot reach Cloudflare — check your outbound firewall rules for HTTPS on port 443.
Common causes and fixes:
STIGIX_REGISTRY_ENABLED=true in .env and restartSTIGIX_TARGET_MASTER_KEY (or the same Prisma TSG ID)8080 on the Leader is reachable from the Peer hosts (firewall / security group)