Lightweight Docker image for Network UPS Tools (NUT) CGI web interface, built on Alpine Linux with security hardening and multi-architecture support.
- Alpine Linux 3.23 - Minimal base image (~50MB vs ~200MB Debian)
- Multi-architecture - Native support for
linux/amd64andlinux/arm64 - Security hardened - Non-root user, pinned dependencies, vulnerability scanning
- Flexible UID support - Works with
--useroverride for volume mount permissions - Enhanced health checks - Three-tier validation of web server and CGI functionality
- Automated updates - Renovate bot manages dependencies with semantic versioning
docker run -d \
--name nut-cgi \
-p 8000:80 \
-v /path/to/hosts.conf:/etc/nut/hosts.conf:ro \
--restart unless-stopped \
ghcr.io/owine/nut-cgi:latestSee docker-compose.yml for a complete example with security hardening.
# Create hosts.conf (see Configuration section)
docker-compose up -dAccess the web interface at: http://localhost:8000
Create a hosts.conf file to define which UPS systems to monitor:
# Monitor local UPS
MONITOR myups@localhost "Living Room UPS"
# Monitor remote UPS systems
MONITOR serverups@192.168.1.100 "Server Rack UPS"
MONITOR officeups@192.168.1.101 "Office UPS"File location: /etc/nut/hosts.conf inside container
See hosts.conf.example for comprehensive examples and configuration tips.
For complete hosts.conf syntax, see NUT documentation.
The container supports two health check modes via the HEALTHCHECK_MODE environment variable:
basic(default): Validates infrastructure only (web server + CGI execution)strict: Validates infrastructure + UPS connectivity (fails if no UPS reachable)
environment:
- HEALTHCHECK_MODE=strict # Require UPS connectivity for healthy statusRun as a specific user ID to match host filesystem permissions:
docker run -d \
--name nut-cgi \
--user 1001:1001 \
-p 8000:80 \
-v /path/to/hosts.conf:/etc/nut/hosts.conf:ro \
ghcr.io/owine/nut-cgi:latestFor production deployments, use security options from the example docker-compose.yml:
- Read-only root filesystem
- Drop all capabilities
- No new privileges
- tmpfs for writable locations
Use specific version tags for production (recommended):
# Pin to exact version
docker pull ghcr.io/owine/nut-cgi:v1.0.0
# Pin to minor version (receives patch updates)
docker pull ghcr.io/owine/nut-cgi:v1.0
# Pin to major version (receives minor/patch updates)
docker pull ghcr.io/owine/nut-cgi:v1Available tags:
:latest- Latest tested release (recommended for production):v1.0.0- Specific semantic version (exact version pinning):v1.0- Latest patch in v1.0.x series:v1- Latest minor in v1.x series:main- Latest tested build from main branch (passes all tests):sha-<commit>- Specific commit build (for debugging/pinning)
- Stage 1 (builder): Minimal preparation stage
- Stage 2 (runtime): Alpine 3.23 with only nut-cgi, lighttpd, and curl
All packages are explicitly version-pinned for reproducibility:
nut-cgi- Network UPS Tools CGI programslighttpd- Lightweight web servercurl- Health check utility
Package versions are automatically updated by Renovate bot with semantic versioning.
Three-tier validation ensures comprehensive health monitoring:
- Tier 1: Web server responding (HTTP 200)
- Tier 2: CGI execution working (non-empty response)
- Tier 3: Valid CGI output (no error content)
Check intervals: 30s | Timeout: 10s | Start period: 15s | Retries: 3
# Clone repository
git clone https://github.com/owine/nut-cgi.git
cd nut-cgi
# Build multi-arch image
docker buildx build --platform linux/amd64,linux/arm64 -t nut-cgi:local .
# Test build locally
docker build -t nut-cgi:test .
docker run --rm -p 8000:80 nut-cgi:testGitHub Actions workflows:
- Lint: Dockerfile (hadolint), YAML, shell scripts
- Build: Multi-arch builds with QEMU, publish to GHCR
- Security: Trivy vulnerability scanning (weekly + post-build)
Renovate bot automatically creates PRs for:
- Alpine base image updates (auto-merge patch versions)
- Alpine package updates (auto-merge revision bumps)
- GitHub Actions updates (auto-merge minor/patch)
Check logs for health check failures:
docker logs nut-cgiCommon issues:
lighttpd not responding- Web server crashed or config errornut-cgi not executing- CGI permissions or missing binarynut-cgi returned error content- Invalid hosts.conf configuration
If running into permission errors with volume mounts:
# Check container's UID/GID
docker exec nut-cgi id
# Run with matching UID/GID
docker run --user $(id -u):$(id -g) ...Ensure file is mounted correctly and readable:
# Verify mount
docker exec nut-cgi ls -la /etc/nut/hosts.conf
# Check file contents
docker exec nut-cgi cat /etc/nut/hosts.confContributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
All PRs must pass linting and build workflows.
MIT License - See LICENSE file for details.
- Original project: danielb7390/nut-cgi
- Network UPS Tools (NUT)
- Alpine Linux
- CHANGELOG.md - Version history and release notes
- SECURITY.md - Security policy and vulnerability reporting
- CLAUDE.md - Development guide and architectural decisions
- hosts.conf.example - Configuration examples
- docs/BUILD_OPTIMIZATION.md - Multi-architecture build optimization guide
- GitHub: https://github.com/owine/nut-cgi
- Container Registry: https://github.com/owine/nut-cgi/pkgs/container/nut-cgi
- Issue Tracker: https://github.com/owine/nut-cgi/issues
- Security Advisories: https://github.com/owine/nut-cgi/security/advisories