Plan: Dockerfile Hygiene — Audit Custom Builds
Status
State: Active Started: 2026-05-14
Context
Sepia has two custom Dockerfiles that are built locally: caddy and collectd. Additionally, the docs container uses a Dockerfile in /opt/docs/Dockerfile. These need a security and best-practices audit.
The collectd Dockerfile is particularly concerning — it runs as root, installs sudo with passwordless access inside the container, uses un-pinned apt with no --no-install-recommends, keeps build dependencies in the final image, and has no healthcheck.
Shuttle has the same plan as active/dockerfile-hygiene.md.
Inventory
| Dockerfile | Path | Base Image | Purpose | Risk |
|---|---|---|---|---|
| caddy | /opt/caddy/Dockerfile |
caddy:2.9-builder + caddy:2.9-alpine |
Multi-stage build with xcaddy plugins | 🟢 Low |
| collectd | /opt/collectd/docker/Dockerfile |
debian:bookworm |
Custom collectd with PMT/hddtemp | 🔴 High |
| docs | /opt/docs/Dockerfile |
python:3.12-slim |
MkDocs documentation server | 🟢 Low |
Goals
- [ ] Fix collectd Dockerfile — non-root user, combined RUNs, remove build deps, add healthcheck
- [ ] Verify caddy Dockerfile is up to standard (looks good — multi-stage, Alpine)
- [ ] Verify docs Dockerfile is up to standard
- [ ] Ensure all custom Dockerfiles have HEALTHCHECK instructions
Steps
Step 1: Fix collectd Dockerfile
The current file has multiple issues:
Problems:
1. Runs as root (CMD starts collectd as root, no USER directive)
2. Installs sudo with passwordless access for collectd user (antipattern)
3. Multiple RUN apt install lines not combined (creates unnecessary layers)
4. No --no-install-recommends (pulls unnecessary packages)
5. Build deps (make, g++, cmake, python3-dev, pybind11) are removed but apt cache remains
6. No HEALTHCHECK
7. HDDTEMP_VERSION is not pinned to a commit/checksum
8. PMT source is copied from build context (COPY PMT /pmt) but directory may not exist in repo
9. apt dist-upgrade in a Dockerfile is unusual and non-reproducible (pulls whatever latest)
10. ENV DEBIAN_FRONTEND=noninteractive should not persist in runtime image
Target (rewrite):
FROM debian:bookworm-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
wget \
make \
g++ \
python3-dev \
python3-pybind11 \
cmake \
&& rm -rf /var/lib/apt/lists/*
# Build hddtemp
ENV HDDTEMP_VERSION=0.3.1
RUN wget -q https://github.com/slowpeek/hddtemp/archive/refs/tags/${HDDTEMP_VERSION}.tar.gz \
&& tar xzf ${HDDTEMP_VERSION}.tar.gz \
&& cd hddtemp-${HDDTEMP_VERSION} \
&& make hddtemp-lt \
&& install hddtemp-lt /usr/sbin/hddtemp \
&& cd / && rm -rf hddtemp-${HDDTEMP_VERSION}*
# Build PMT
COPY PMT /pmt
RUN cmake -S/pmt -B/pmt/build -DPMT_BUILD_RAPL=1 -DPMT_BUILD_BINARY=1 -DPMT_BUILD_PYTHON=1 -DCMAKE_INSTALL_PREFIX=/opt/pmt \
&& make -C/pmt/build -j install \
&& rm -rf /pmt
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
collectd \
libsensors5 \
liblzo2-2 \
btrfs-progs \
libatasmart4 \
speedtest-cli \
smartmontools \
wget \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/sbin/hddtemp /usr/sbin/hddtemp
COPY --from=builder /opt/pmt /opt/pmt
ENV LD_LIBRARY_PATH="/opt/pmt/lib"
ENV PYTHONPATH="/opt/pmt/lib/python3.11/site-packages"
ENV PATH="$PATH:/opt/pmt/bin"
USER nobody
HEALTHCHECK NONE
CMD ["/usr/sbin/collectd", "-f"]
Note: PMT source directory (/opt/collectd/docker/PMT/) must exist in the repo for the build to work.
- Verification:
docker build -t collectd:bookworm /opt/collectd/docker/ && docker run --rm collectd:bookworm collectd -hsucceeds, runs as non-root
Step 2: Verify Caddy Dockerfile
Current file is already good:
- ✅ Multi-stage build (builder → runtime)
- ✅ Minimal base (caddy:2.9-alpine)
- ✅ Clean separation of build and runtime
Check if plugins need updating:
github.com/caddy-dns/route53
github.com/mholt/caddy-dynamicdns
github.com/zhangjiayin/caddy-geoip2
github.com/mholt/caddy-l4
github.com/greenpau/caddy-security
Consider adding:
- HEALTHCHECK --interval=30s --timeout=10s CMD ["wget", "--spider", "http://localhost:2019/config/"]
- Pin caddy builder/runtime base image digests for reproducibility
- Verification:
docker build -t caddy /opt/caddy/ && docker run --rm caddy --versionworks
Step 3: Verify Docs Dockerfile
Current file:
- ✅ Good base (python:3.12-slim)
- ✅ Installs only needed packages
- ✅ Cleans apt cache in same layer
Consider adding:
- HEALTHCHECK --interval=30s --timeout=10s CMD ["curl", "-f", "http://localhost:8000/"]
- Pin pip package versions instead of --no-cache-dir latest
- Run as non-root user
- Verification:
docker build -t opt-docs /opt/docs/succeeds
Step 4: Add HEALTHCHECK to All Custom Dockerfiles
| Dockerfile | Proposed HEALTHCHECK |
|---|---|
| caddy | wget --spider http://localhost:2019/config/ |
| collectd | None (no HTTP endpoint) — or pidof collectd |
| docs | curl -f http://localhost:8000/ (already has similar in compose) |
Rollback
- Git revert for any Dockerfile changes
docker compose build <service>to rebuild with previous Dockerfile
Related
- PLANS/active/infrastructure-hardening.md (healthchecks for all services)
- REFERENCE/services.md
Created: 2026-05-14