Your homelab runs dozens of Docker containers. Each image pulls in layers from upstream registries — Alpine, Debian, nginx, Python, PostgreSQL. And every layer can ship with known vulnerabilities that get discovered months after you pulled it.
Manual audits don’t scale. You need an automated scanner that checks every running image against the latest CVE databases, flags misconfigurations, detects embedded secrets, and generates reports you can actually act on.
Trivy from Aqua Security does all of this. It is fast, dependency-free (one binary or a container), covers OS packages and language-specific libraries, and integrates cleanly into a homelab automation workflow. This guide walks through installation, scanning workflows, output formats, and a complete systemd timer setup for weekly unattended scans.
Installing Trivy
Trivy ships as a single static binary, a Docker image, and packages for every major distro. For a Proxmox or bare-metal Linux host, install the binary directly — it avoids the overhead of scanning images from inside a container.
Debian/Ubuntu Repository Install
|
|
Docker-based Usage
|
|
Verify Installation
|
|
Trivy downloads a vulnerability database on first run. The database is
cached under ~/.cache/trivy and updated automatically when you scan
with a DB older than 12 hours. You can force an update with:
|
|
Scanning Running Docker Images
The most useful scan for a homelab: check every image currently running for known CVEs.
Scan a Single Image
|
|
This produces a severity-sorted table of every CVE found in the OS packages inside that image. Critical findings are highlighted in red.
Scan All Running Containers
Combine docker ps with Trivy to scan your entire runtime:
|
|
Add --ignore-unfixed to skip CVEs that have no available fix — this
reduces noise significantly in production-style scans.
|
|
Example Output
nginx:1.27-alpine (alpine 3.21.3)
===============================
Total: 3 (HIGH: 2, CRITICAL: 1)
┌──────────┬────────────────┬──────────┬──────────────┬───────────────┐
│ Library │ Vulnerability │ Severity │ Installed Ver│ Fixed Version │
├──────────┼────────────────┼──────────┼──────────────┼───────────────┤
│ libcrypto3│ CVE-2026-1234 │ CRITICAL │ 3.3.0-r0 │ 3.3.1-r0 │
│ libssl3 │ CVE-2026-1235 │ HIGH │ 3.3.0-r0 │ 3.3.1-r0 │
│ zlib │ CVE-2026-1236 │ HIGH │ 1.3.1-r0 │ 1.3.2-r0 │
└──────────┴────────────────┴──────────┴──────────────┴───────────────┘
Scanning for Misconfigurations and Secrets
Trivy is not just for CVEs. It also scans Dockerfiles and docker-compose files for misconfigurations and hardcoded secrets.
Scan Dockerfile Misconfigurations
|
|
This catches issues like:
- Containers running as root when they don’t need to
- Missing health checks
- Exposed ports without documented purpose
- Privileged mode without justification
- Environment variables that look like secrets
Scan for Secrets in Images
|
|
The secrets scanner checks for embedded API keys, tokens, passwords, and private keys in image layers. Useful before pushing custom images to a registry.
Full Multi-Scanner Run
|
|
Generating Actionable Reports
Plain terminal output is fine for interactive use, but for automated scans you want formats you can archive, email, or visualize.
HTML Report
|
|
Install the template first:
|
|
JSON Report for Scripting
|
|
Use jq to extract only critical findings:
|
|
SARIF Output for IDE Integration
|
|
SARIF files can be opened in VS Code with the SARIF viewer extension.
Automating Weekly Scans with Systemd Timers
The most valuable setup for a homelab: unattended weekly scans that email or log results. Systemd timers are the cleanest way on Linux.
Create the Scan Script
|
|
Write /opt/trivy-scanner/scan-all.sh:
|
|
Make it executable:
|
|
Create the Systemd Service
/etc/systemd/system/trivy-scan.service:
|
|
The Nice=19 and IOSchedulingClass=idle lines ensure the scan
doesn’t compete with production workloads.
Create the Systemd Timer
/etc/systemd/system/trivy-scan.timer:
|
|
Enable and start:
|
|
Check Timer Status
|
|
Cron Alternative for Simpler Setups
If systemd timers feel heavy, a cron job works just as well:
|
|
Add with crontab -e or drop a file in /etc/cron.weekly/.
Integrating with a Monitoring Dashboard
Trivy JSON output can be visualized in Grafana or Grafana Alloy. A lightweight alternative: serve the HTML reports with a one-liner HTTP server and catch them in your monitoring stack.
Serve Reports via Docker
|
|
Then check http://homelab-host:8088 for the latest scan reports.
Extract Key Metrics with jq
|
|
Keeping Images Up to Date
Scanning is only half the battle. When Trivy flags a critical CVE, the fix is almost always a newer version of the base image. A practical workflow:
- Scan runs weekly, report lands in
/var/log/trivy-reports/ - Review report for
CRITICALfindings where a fix exists - Pull the fixed image:
docker pull nginx:1.27-alpine - Recreate containers:
docker compose up -d - Re-run scan to confirm all CVEs are resolved
For images you build yourself, rebuild with updated base images and redeploy. If you run Watchtower (covered in a previous post), it can handle the pulling step automatically — but Trivy gives you the visibility to decide which updates matter.
Key Takeaways
- Trivy scans images, filesystems, configs, and secrets — it is the single tool you need for container security in a homelab.
- Use
--severity HIGH,CRITICAL --ignore-unfixedto focus on actionable findings and ignore noise. - Systemd timers with idle scheduling run scans without disrupting
workloads.
Nice=19keeps CPU impact minimal. - HTML or JSON reports make results reviewable at a glance and storable for trend analysis.
- Scan first, then update — Trivy tells you what to fix. Your image update strategy (Watchtower, manual pull, or rebuild) closes the loop.
Security is a process, not a one-time task. An automated weekly scan with Trivy keeps your homelab safe with minimal effort — and gives you the confidence that your containers aren’t running known-critical vulnerabilities between updates.