Skip to content
This repository was archived by the owner on Aug 8, 2026. It is now read-only.

Migrate to Debian, run non-root, split CI, align with org scaffolding - #64

Merged
modem7 merged 2 commits into
masterfrom
modernize-debian-migration
Aug 8, 2026
Merged

modem7 merged 2 commits into
masterfrom
modernize-debian-migration

Conversation

@modem7

@modem7 modem7 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Base image: Alpine → debian:trixie-slim. Alpine dropped the dhcrelay package entirely starting at 3.21 (confirmed empirically against 3.21/3.22/3.23/3.24 - it's just gone). Upstream ISC-DHCP has had no releases since 2022 (#63), but Debian still packages and security-patches isc-dhcp-relay, so this keeps the image receiving real security fixes going forward instead of being stuck on an ancient Alpine branch.
  • Non-root runtime, verified. setcap cap_net_raw,cap_net_bind_service+eip on the dhcrelay binary + a non-root USER, with compose cap_drop: ALL + cap_add: [NET_RAW, NET_BIND_SERVICE]. Tested against a real interface: binds UDP/67 and relays correctly as uid=999. The previous NET_ADMIN grant turned out to be unnecessary - confirmed by testing, not assumed.
  • Env-var driven config, without breaking existing setups: entrypoint.sh builds the dhcrelay command line from DHCRELAY_DOWN_INTERFACE/DHCRELAY_UP_INTERFACE/DHCRELAY_SERVERS/DHCRELAY_MODE/DHCRELAY_EXTRA_ARGS, but if a command: is given (the old style), it's passed straight through untouched.
  • Real healthcheck. The old commented-out nc -uzvw3 one wouldn't have worked - dhcrelay uses raw AF_PACKET sockets, not a connectable UDP listener. Now checks that PID 1 is still dhcrelay.
  • CI split, per your instruction:
    • .github/workflows/lint.yml - hadolint on GitHub Actions (was in Drone).
    • .woodpecker.yml (replacing .drone.yml) - build/push/pushrm/slack, triggered on push-to-master + manual, mirroring docker-borgmatic/docker-starwars. Tags now resolve the actual isc-dhcp-relay version installed (e.g. 4.4.3) instead of a hardcoded, driftable one.
    • .github/workflows/dhcrelay-freshness.yml - weekly check comparing Debian's current package version against the published image tag; opens a tracking issue if stale (mirrors docker-starwars' content-freshness pattern). Rebuild stays a manual Woodpecker trigger rather than a silent auto-push.
  • Org scaffolding alignment: .github/settings.yml (_extends: .github), autoassign.yml now handles PRs too (excluding renovate[bot]), labelsync.yml/labels.yml removed (labels now inherited from the account-wide settings), renovate.json now just extends github>modem7/renovate-config (no local digest pinning - matches the preset repo's documented convention).
  • Cleanup: removed Links/ and version_check.txt (Alpine-specific, dead now).
  • Docs: README compose example, env var table, and split DHCPv4/DHCPv6 command examples updated to match.

Closes #63.

Test plan

  • docker build succeeds; hadolint and shellcheck both clean.
  • Passthrough mode (command: [...], old-style) verified: relay starts, listens/sends on a real interface.
  • Env-var mode verified: same, with DHCRELAY_DOWN_INTERFACE/DHCRELAY_UP_INTERFACE/DHCRELAY_SERVERS.
  • Missing required env vars fails fast with a clear message (exit 1).
  • Confirmed non-root (uid=999) with only NET_RAW+NET_BIND_SERVICE, binds UDP/67.
  • HEALTHCHECK reports healthy while the relay is running.
  • Woodpecker pipeline run (needs the PR merged/pipeline triggered to confirm prepare-tags/build-and-push end to end).
  • Real-world DHCP relay traffic on your actual eno1/br_pihole setup, since I could only test with synthetic interfaces here.

Alpine dropped the dhcrelay package entirely starting at 3.21 (upstream
ISC-DHCP has had no releases since 2022); Debian trixie still ships and
security-patches isc-dhcp-relay, so that's the new base. The process now
runs as a non-root user with only NET_RAW/NET_BIND_SERVICE via setcap,
verified empirically to still bind port 67 and relay correctly (NET_ADMIN,
previously granted, turns out to be unnecessary).

- Dockerfile: debian:trixie-slim, setcap+non-root, OCI labels, a real
  pgrep-free healthcheck, and an entrypoint.sh that builds the dhcrelay
  command from DHCRELAY_* env vars (falling back to passthrough for any
  explicit command, so existing compose overrides keep working).
- docker-compose.yml: cap_drop: ALL + minimal cap_add, env-var config,
  drops the obsolete `version:` key.
- CI split: hadolint now lives in .github/workflows/lint.yml (GitHub
  Actions); .woodpecker.yml (replacing .drone.yml) builds/pushes on
  push-to-master + manual events, tagging images with the resolved
  isc-dhcp-relay version instead of a hardcoded one.
- .github/workflows/dhcrelay-freshness.yml: weekly check comparing
  Debian's current package version against the published image tag,
  opens a tracking issue if stale (manual Woodpecker rebuild fixes it).
- renovate.json now just extends the shared org preset; .hadolint.yaml
  overrides DL3008 for the intentionally-unpinned package.
- .github/settings.yml + autoassign.yml brought in line with the rest of
  the account (labelsync.yml/labels.yml removed, now inherited via
  settings.yml).
- README updated for the new compose shape, env vars, and split
  DHCPv4/DHCPv6 command examples; removed the now-unused Links/ and
  version_check.txt (Alpine-specific).

Addresses #63.
Adds a maintenance-mode notice with a placeholder link to the future
Kea-based repo, and a "What changed" summary of the non-root/healthcheck/
env-var/freshness-check work from this PR.
@modem7
modem7 merged commit eca9681 into master Aug 8, 2026
2 checks passed
@modem7
modem7 deleted the modernize-debian-migration branch August 8, 2026 12:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ISC DHCP Server has reached EOL

1 participant