diff --git a/Dockerfile b/Dockerfile index 77510a0..45027be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,8 +68,12 @@ RUN apk add --no-cache \ COPY --from=builder /pixad /usr/local/bin/pixad COPY deploy/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh -# Create non-root user, config directory, and data directory -RUN adduser -D -H -s /sbin/nologin pixad && \ +# Create non-root user, config directory, and data directory. pixad +# gets uid and gid 65532, which host login and system accounts do not +# use: a bind-mounted /var/lib/pixa is given to pixad, and on the host +# it must not belong to a person's account. +RUN addgroup -g 65532 pixad && \ + adduser -D -H -s /sbin/nologin -u 65532 -G pixad pixad && \ mkdir -p /var/lib/pixa /etc/pixa && \ chown pixad:pixad /var/lib/pixa diff --git a/README.md b/README.md index 23fe41b..ec673d1 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,10 @@ What the [upaas](https://git.eeqj.de/sneak/upaas) app for pixa needs: `healthy`. The probe uses the port from `PORT` (default `8080`), so a port changed only in a mounted config file is not seen by it: change the port with `PORT`. -- **First run:** create the host directory. It may be owned by root: the - container gives it to its `pixad` user when it starts. +- **First run:** create the host directory, owned by root or by uid + `65532` and gid `65532`. The server runs as the container's `pixad` + user, which has that uid and gid, and the container gives the + directory to `pixad` when it starts. ## Rationale diff --git a/TODO.md b/TODO.md index c10609b..a8ec7c3 100644 --- a/TODO.md +++ b/TODO.md @@ -30,6 +30,11 @@ exhaustion # Completed Steps +- 2026-09-29 fixed uid and gid for `pixad` (closes #151): the image creates the + `pixad` group with gid 65532 and the `pixad` user with uid 65532, instead of + the first free uid 1000, so a bind-mounted `/var/lib/pixa` given to `pixad` + is not owned on the host by a person's login account; the first-run step of + "Running under upaas" in `README.md` names the uid and gid. - 2026-09-29 `max-age` never outlives an expiring URL (closes #63): both image routes build `Cache-Control` from the request's `Expires`, which an encrypted URL's expiry now fills too; `max-age` is one year, or the whole seconds left