diff --git a/Dockerfile b/Dockerfile index 8451b56..77510a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,17 +61,20 @@ RUN apk add --no-cache \ vips \ libheif \ ca-certificates \ - tzdata + tzdata \ + su-exec # Copy binary from builder 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 && \ mkdir -p /var/lib/pixa /etc/pixa && \ chown pixad:pixad /var/lib/pixa -USER pixad +# No USER: the entrypoint must start as root to give a bind-mounted +# /var/lib/pixa to pixad; it then runs the server as pixad. WORKDIR /var/lib/pixa EXPOSE 8080 @@ -84,4 +87,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ # Settings come from PORT and the PIXA_ environment variables; only # PIXA_SIGNING_KEY is required. A config file mounted at # /etc/pixa/config.yml is optional and is read when present. -ENTRYPOINT ["/usr/local/bin/pixad"] +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] diff --git a/README.md b/README.md index d3b2b13..681a624 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,33 @@ else has a built-in default. A config file mounted at `/etc/pixa/config.yml` is optional: it is read when present, and an environment variable wins over the same setting in it. +## Running under upaas + +What the [upaas](https://git.eeqj.de/sneak/upaas) app for pixa needs: + +- **Port:** pixa listens on container port `8080`. +- **Volume:** container path `/var/lib/pixa`, where pixa keeps its + database and cache. upaas bind-mounts the host path it is given and + does not create it, so the host directory must exist before the first + deploy. +- **Environment variables:** + - `PIXA_SIGNING_KEY` (required): secret for signed and encrypted URLs + and login, 32+ characters, for example from + `openssl rand -base64 32` + - `PIXA_ALLOWLIST_HOSTS`: upstream hosts served without a signature, + comma-separated + - `PIXA_CACHE_MAX_BYTES`: disk cache limit in bytes; `0` disables it; + default 75% of free space + - the rest are in the table under Configuration below +- **Health check:** the image's `HEALTHCHECK` requests + `/.well-known/healthcheck.json`. upaas reads the container's health 60 + seconds after a deploy and marks the deploy failed unless it is + `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. + ## Rationale Image-heavy web applications need a fast, caching reverse proxy that diff --git a/TODO.md b/TODO.md index e859d2e..6141de2 100644 --- a/TODO.md +++ b/TODO.md @@ -30,6 +30,12 @@ exhaustion # Completed Steps +- 2026-09-28 start on a fresh upaas volume (closes #129): the image + starts as root only to give `/var/lib/pixa` to `pixad` when `pixad` + does not own it (`deploy/docker-entrypoint.sh`), then runs the server + as `pixad` through `su-exec`, so a root-owned host directory + bind-mounted there no longer stops the container at startup; + `README.md` gains a "Running under upaas" section. - 2026-09-28 run all linting in Docker via `Dockerfile.lint` + `script/lint` (closes #104): `make lint` calls `script/lint`, the only way the linter is run; inside a container (both Dockerfiles set diff --git a/deploy/docker-entrypoint.sh b/deploy/docker-entrypoint.sh new file mode 100755 index 0000000..691ff2f --- /dev/null +++ b/deploy/docker-entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# deploy/docker-entrypoint.sh: the Docker image's ENTRYPOINT. It runs as +# root only to give /var/lib/pixa to pixad: a host directory +# bind-mounted there keeps its host owner, often root, and pixad could +# not write to it. The server itself always runs as pixad. +set -eu + +main() { + if [ "$(stat -c %U /var/lib/pixa)" != pixad ]; then + chown pixad:pixad /var/lib/pixa + fi + exec su-exec pixad /usr/local/bin/pixad "$@" +} + +main "$@"