Start on a fresh upaas volume and document running under upaas (closes #129)
check / check (push) Successful in 11s

upaas bind-mounts an existing host directory and sets no container
user, so a directory made with mkdir as root left pixad unable to
write /var/lib/pixa, and the container exited at startup.

The image now starts as root: deploy/docker-entrypoint.sh gives
/var/lib/pixa to pixad when pixad does not own it, then runs the
server as pixad through su-exec (alpine's package), so the server
never runs as root. README.md gains a "Running under upaas" section:
port, volume, environment variables, health check, first-run step.

Model: opus-5-5
This commit was merged in pull request #135.
This commit is contained in:
2026-09-28 15:12:48 +02:00
parent 2f7365cc9b
commit 50123b2a6d
4 changed files with 54 additions and 3 deletions
+6 -3
View File
@@ -61,17 +61,20 @@ RUN apk add --no-cache \
vips \ vips \
libheif \ libheif \
ca-certificates \ ca-certificates \
tzdata tzdata \
su-exec
# Copy binary from builder # Copy binary from builder
COPY --from=builder /pixad /usr/local/bin/pixad 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 # Create non-root user, config directory, and data directory
RUN adduser -D -H -s /sbin/nologin pixad && \ RUN adduser -D -H -s /sbin/nologin pixad && \
mkdir -p /var/lib/pixa /etc/pixa && \ mkdir -p /var/lib/pixa /etc/pixa && \
chown pixad:pixad /var/lib/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 WORKDIR /var/lib/pixa
EXPOSE 8080 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 # Settings come from PORT and the PIXA_ environment variables; only
# PIXA_SIGNING_KEY is required. A config file mounted at # PIXA_SIGNING_KEY is required. A config file mounted at
# /etc/pixa/config.yml is optional and is read when present. # /etc/pixa/config.yml is optional and is read when present.
ENTRYPOINT ["/usr/local/bin/pixad"] ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
+27
View File
@@ -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 is optional: it is read when present, and an environment variable wins over
the same setting in it. 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 ## Rationale
Image-heavy web applications need a fast, caching reverse proxy that Image-heavy web applications need a fast, caching reverse proxy that
+6
View File
@@ -30,6 +30,12 @@ exhaustion
# Completed Steps # 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` + - 2026-09-28 run all linting in Docker via `Dockerfile.lint` +
`script/lint` (closes #104): `make lint` calls `script/lint`, the only `script/lint` (closes #104): `make lint` calls `script/lint`, the only
way the linter is run; inside a container (both Dockerfiles set way the linter is run; inside a container (both Dockerfiles set
+15
View File
@@ -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 "$@"