Summary
The Caddy container currently runs as root inside the container, hardened with cap_drop: ALL and cap_add: NET_BIND_SERVICE. Switching to a non-root user would be a small defense-in-depth improvement and would remove the requirement that caddy_data / caddy_config be root-owned on the host.
Context
The current model is already well-hardened: container-root has no capabilities beyond NET_BIND_SERVICE, so it cannot bypass file modes or do anything privileged. A container escape would land the attacker on the host as UID 0 anyway — that's a runtime/kernel concern, not an in-container UID concern. The reason this came up: during the recent restructure, a chown -R stoga:stoga broke Caddy because container-root, without CAP_DAC_OVERRIDE, couldn't read mode-0600 cert files owned by UID 1000. Running the container as UID 1000 would make the data dirs naturally stoga-owned and avoid this kind of footgun.
Scope
- Set
user: 1000:1000 on the caddy service
- Make binding ports 80 and 443 work: either bake
setcap cap_net_bind_service+ep into a derived image, set sysctl net.ipv4.ip_unprivileged_port_start=80 on the host, or run Caddy on high ports and forward
- Re-chown
caddy_data and caddy_config to 1000:1000
Acceptance criteria
Notes
Draft / backlog. Marginal security gain. The official Caddy image documents running as root; going non-root is off the happy path. Filing so the rationale is preserved and we can revisit if the host-config footprint becomes worth carrying.
Summary
The Caddy container currently runs as root inside the container, hardened with
cap_drop: ALLandcap_add: NET_BIND_SERVICE. Switching to a non-root user would be a small defense-in-depth improvement and would remove the requirement thatcaddy_data/caddy_configbe root-owned on the host.Context
The current model is already well-hardened: container-root has no capabilities beyond
NET_BIND_SERVICE, so it cannot bypass file modes or do anything privileged. A container escape would land the attacker on the host as UID 0 anyway — that's a runtime/kernel concern, not an in-container UID concern. The reason this came up: during the recent restructure, achown -R stoga:stogabroke Caddy because container-root, withoutCAP_DAC_OVERRIDE, couldn't read mode-0600 cert files owned by UID 1000. Running the container as UID 1000 would make the data dirs naturallystoga-owned and avoid this kind of footgun.Scope
user: 1000:1000on the caddy servicesetcap cap_net_bind_service+epinto a derived image, setsysctl net.ipv4.ip_unprivileged_port_start=80on the host, or run Caddy on high ports and forwardcaddy_dataandcaddy_configto1000:1000Acceptance criteria
up1000:1000, no sudo needed for routine opsNotes
Draft / backlog. Marginal security gain. The official Caddy image documents running as root; going non-root is off the happy path. Filing so the rationale is preserved and we can revisit if the host-config footprint becomes worth carrying.