Getting Started
This tutorial walks you through your first inspectah scan. By the end, you will have scanned a host, reviewed the output artifacts, and opened the refine UI to triage findings. Total time: about 10 minutes.
Prerequisites
- A Fedora, CentOS Stream, or RHEL host (the system you want to migrate)
- Podman installed (
dnf install podman) - Root access on the target host (inspectah reads system configuration)
For RHEL users: inspectah pulls the matching base image to classify findings. RHEL base images require registry authentication:
sudo podman login registry.redhat.io
Fedora and CentOS Stream base images are available from public registries and do not require authentication. If you skip registry auth on RHEL, inspectah will fail to pull the baseline image.
For disconnected or air-gapped environments: Pull the base image on a connected machine, save it as a tarball (podman save -o baseline.tar <image-ref>), transfer the tarball to your target host, and load it (podman load -i baseline.tar). Alternatively, configure a local or mirror registry.
Install inspectah
RPM (Fedora / RHEL / CentOS Stream)
sudo dnf copr enable mrussell/inspectah
sudo dnf install inspectah
macOS (Homebrew)
brew tap marrusl/inspectah
brew install inspectah
Apple Silicon only. For Intel Macs, build from source below.
From source
git clone https://github.com/marrusl/inspectah.git
cd inspectah
cargo build --release -p inspectah-cli
sudo install target/release/inspectah /usr/local/bin/
Requires Rust 1.80+ and a C linker.
Verify the install:
inspectah version
You should see the version number, git commit, and build date.
How inspectah works
Before diving into the commands, here is a visual overview of what inspectah does when you scan a host:
Scan your first host
Run inspectah as root on the system you want to migrate:
sudo inspectah scan
inspectah runs a four-stage pipeline:
- Detect the OS and resolve a matching base image
- Pull the base image (you will see download progress)
- Inspect the system — RPMs, configs, services, users, repos, containers, storage, and more (11 inspectors by default)
- Render migration artifacts and package them into a tarball
A typical scan takes 30–90 seconds depending on the number of installed packages and network speed for the base image pull. On subsequent runs, the base image is cached locally.
When the scan finishes, you will see output like:
✓ RPM packages 847 packages, 6 repos
✓ Services 27 units
✓ Storage done
✓ Kernel & boot done
✓ Network done
✓ Containers 2 found
✓ Users & groups done
✓ Scheduled tasks done
✓ Config files 12 modified
✓ SELinux done
✓ Non-RPM packages 2 ecosystems
pip packages 23 · npm packages 69 · 1 repo-less RPM (cached)
┄┄┄
12 modified configs · 23 pip packages · 69 npm packages · 1 repo-less
Inspected in 42.3s
Report: myhost-20260527-143000.tar.gz
To review: inspectah refine myhost-20260527-143000.tar.gz
The tarball is written to your current directory. The filename includes the hostname and a timestamp.
Understand the output
Extract the tarball to see what inspectah produced:
tar tzf myhost-*.tar.gz
Key files inside:
| File | Purpose |
|---|---|
Containerfile | Image build definition — the starting point for podman build |
audit-report.md | Findings summary: what was detected, storage plan, version drift |
audit-report.html | HTML audit report of all findings |
secrets-review.md | Details of redacted sensitive content for your review |
README.md | Build commands and a FIXME checklist |
kickstart-suggestion.ks | Deploy-time settings (network, storage, boot) |
inspection-snapshot.json | Structured data — the full snapshot, re-renderable |
config/ | Modified config files to COPY into the image |
Conditional files may also appear depending on your system: quadlet/ for container workloads, language-packages/ for pip/npm/gem environments, repoless-packages/ for RPMs with no repository source, inspectah-users.toml / inspectah-users.ks for user and group definitions, and subscription/ for RHEL subscription data.
For a complete description of every artifact, see Output Artifacts.
Beyond RPMs
inspectah detects language packages (pip, npm, gem) automatically. The Containerfile includes install directives for detected environments, with confidence levels that control whether directives are active, commented-out, or advisory. See Handle Non-RPM Software for details.
To also capture files under /opt, /srv, /usr/local that are not managed by any package manager, add --include-unmanaged:
sudo inspectah scan --include-unmanaged
Packages installed from local .rpm files or disabled repositories are flagged automatically. See Handle Repo-less RPMs for the upload and resolution workflow.
Open the refine UI
The refine command starts a local web server so you can review and curate the scan findings in your browser:
inspectah refine myhost-*.tar.gz
You will see:
Loading snapshot...
Starting refine server on http://127.0.0.1:8642
Press Ctrl-C to stop.
Your browser opens automatically. If it does not, navigate to http://127.0.0.1:8642 manually.
The refine UI shows every finding organized by section (packages, configs, services, language packages, unmanaged files, etc.). Each item has a triage classification and an include/exclude toggle. Your changes are autosaved – close the browser and stop the server with Ctrl-C when you are done.
If you are accessing a remote host over SSH, forward the port:
ssh -L 8642:localhost:8642 user@remote-host
Then open http://127.0.0.1:8642 in your local browser.
Understand triage classifications
inspectah classifies every finding into one of three buckets:
| Classification | Meaning | Action |
|---|---|---|
| Baseline | Already provided by the base image — no action needed | Excluded from the Containerfile (subtracted from scope) |
| Site | Specific to this host — likely needs to be carried forward | Included in the Containerfile by default |
| Investigate | Ambiguous — inspectah could not confidently classify it | Review manually and decide include or exclude |
Baseline subtraction is the core value of running inspectah against a known base image. Instead of migrating everything, you only carry forward what the base image does not already provide.
For details on how classification works and the aggregate-level extensions (Universal, Partial, Divergent), see Triage Classification.
Next steps
You have scanned a host, reviewed the output, and seen the triage model in action. From here:
- Review and refine findings — use the refine UI to curate include/exclude decisions. See How to Review and Refine.
- Build a bootc image — use
inspectah buildto build the image directly from the scan tarball, or usepodman buildmanually with the generated Containerfile. See How to Build a bootc Image. - Roll up multiple hosts — migrating more than one system? Scan them all and aggregate the results to find common patterns. See How to Aggregate Multiple Hosts.
- Handle non-RPM software — pip, npm, and gem packages are detected automatically. See Handle Non-RPM Software.
- Resolve repo-less packages — packages without a repository source need manual handling. See Handle Repo-less RPMs.
- Explore the full CLI — see all available commands and flags in the CLI Reference.