mipo
Guide

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

Users and scanner bootstrap traffic (provisioning and enrollment) arrive at :443, where the main Traefik terminates TLS. It routes /scanner/* and /discovery/* to the ingest nodes and everything else to the manager (the GUI and admin API, authenticated with session cookies). Scanner and resolver runtime traffic — heartbeats, job claims, results, certificate renewal — arrives at :8443, a dedicated Traefik process that requires a client certificate on every handshake. It routes /scanner/* to ingest and /scanner/cert* to the manager, which owns the certificate lifecycle. Scanners authenticate with that client certificate plus their API key; a firewall between a scanner host and mipo must allow both ports (see Scanner ACL).

Request path
Edge
Users + scanner bootstrap → :443 TraefikScanners / resolvers → :8443 Traefik (mTLS)
Two Traefik processes. :443 terminates TLS for users and for scanner provisioning/enrollment; a dedicated :8443 process requires a client certificate on every handshake and routes /scanner/* to ingest and /scanner/cert* to the manager.
↓
Services
Manager (GUI + admin API)Ingest ×2 (scanner API)Dispatcher (orchestration)Maintenance (evidence retention)Watchdog (platform health)
Session cookies for users; client certificates (mTLS) plus a per-scanner API key for scanners. The Node services run from one image selected by a ROLE variable.
↓
Data
db (TimescaleDB cluster)config / results / jobs schemasPer-service database roles
One TimescaleDB cluster with three schemas on an isolated internal network with no outbound internet; hypertables live only in the results schema. Each app service connects as its own role, and the evidence tables are append-only for every app role.
Separate infrastructure
Public siteNot behind Traefik
mipo.network (Astro static)
The marketing/docs site deploys to separate infrastructure, NOT behind Traefik.

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 and resolvers, and serve the discovery-source push API (/discovery/lists/*) that external inventories post addresses to. The dispatcher is a singleton that orchestrates scans — resolving templates into concrete targets, expanding CIDR ranges, batching jobs across scanners, queueing reverse-DNS lookups, and reconciling stalls. The backup service performs scheduled database backups, encrypted when a backup encryption key is configured, and exposes an internal-only HTTP API; restore is a separate path, the operator CLI scripts/ops/restore.sh, which connects as the database owner (the setup wizard's restore exists only where the manager is given owner credentials, which the production compose does not do).

Four more services complete a production deployment. The maintenance service is the only long-running process that connects as the database owner: it prunes evidence past its retention window and has no HTTP port. The migrator is a one-shot container run before the app starts; it applies forward-only schema migrations, reconciles the per-service role grants, and offers a preflight safety check that upgrades use as a gate. The watchdog is a sidecar that restarts unhealthy containers, collects metrics, and publishes the scanner trust bundle to the edge. A second Traefik process, traefik-scanner-mtls, serves the :8443 scanner ingress described above, kept separate so its mandatory client-certificate requirement can never be relaxed by the main edge's configuration. The manager, ingest, dispatcher, maintenance and migrator all run from one application image, selected per container by a ROLE variable; backup and watchdog are separate images.

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 (scan and DNS orchestration state plus the append-only execution receipts). The cluster lives on an isolated internal network with no outbound internet — it cannot be reached from outside or reach out itself.

Each application service connects as its own database role with its own password — the manager, ingest, dispatcher and watchdog hold only their role's credentials, so a compromised process cannot log in as the cluster owner. The evidence tables — audit events, scan results, scan and DNS job receipts, and DNS observations — are append-only for every application role: no role holds update or delete privileges, and a database trigger rejects mutation even on a privileged path. Only the separate maintenance service, running as the owner, removes evidence, and only once it has passed its retention window.

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. Resolver identities (reverse-DNS workers) share this whole lifecycle — provisioning, heartbeats, mTLS, revocation — but the dispatcher never hands them port work. When a scan template (or the global default in Admin > Settings) requests reverse DNS, the dispatcher derives the hosts from the scan, bundles DNS jobs per resolver group, and the resolvers in that group claim them through ingest, run PTR lookups against their host's DNS or a configured nameserver group, and submit observation batches plus a signed receipt per job. See Resolvers, Resolver Groups and Nameserver Groups.