Architecture
mipo is a small set of cooperating containers behind a single TLS edge, backed by one TimescaleDB cluster (three purpose-built schemas) on an isolated network. The public website (this site) runs on entirely separate infrastructure.
Request path
All traffic arrives at :443 and is terminated by Traefik. Traefik routes /scanner/*
to the ingest nodes (the scanner API, authenticated with API keys) and everything else to the manager (the
GUI and admin API, authenticated with session cookies). Both APIs share the external port but live behind
different path prefixes.
The public website (this site) is static HTML/CSS/JS deployed to its own host. It shares no runtime, no database, and no request path with the mipo application.
Services
The manager serves the GUI and admin API as a single instance. Two ingest
nodes handle heartbeats, job dispatch, and result collection from scanners. The dispatcher
is a singleton that orchestrates scans — resolving templates into concrete targets, expanding CIDR ranges,
batching jobs across scanners, and reconciling stalls. The backup service performs encrypted
database backups and exposes an internal-only HTTP API; restore is a separate path (the Day-0 manager
route and the operator CLI scripts/ops/restore.sh).
Data layer
One TimescaleDB cluster holds three schemas that isolate concerns by access pattern: config (low-volume complex queries), results (TimescaleDB hypertables, time-series scan data retained for historical diffing), and jobs (transient orchestration state). The cluster lives on an isolated internal network with no outbound internet — it cannot be reached from outside or reach out itself.
Website separation
The marketing and docs site is Astro static output deployed to its own host. It is not behind Traefik, shares no runtime, database, or request path with the application, and serves only pure HTML, CSS, and JavaScript. This keeps the public surface entirely decoupled from the operational system.
Scanner lifecycle
Scanners are provisioned via a one-time install command, then heartbeat every 60 seconds (2 minutes of silence marks them offline). The dispatcher fans fully-resolved jobs out to the right scanners; for scanner groups it creates a separate job per scanner so the same targets are scanned from every vantage point. Scanners stream results back through ingest and never write the database directly. A background reconciler flags stalled jobs and emits recovery events.