fix: [outline] align datastore ownership with the application user
Outline runs as an unprivileged user in the image (``nodejs`` since 1.10.0, ``root`` up to 1.6.1) while the datastore is provisioned by ``root``. Without realignment the application cannot write its ``uploads``, ``public`` and ``avatars`` buckets, so every attachment upload fails with "Permission denied writing to ... Check the host machine file system permissions". This was seen on elabore.coop after the 1.6.1 to 1.10.0 upgrade. The ``init`` hook now reads the image's ``Config.User`` and chowns the datastore to that user, skipping root-based images. It is idempotent and version-agnostic: the realignment also covers buckets added by future Outline versions.
This commit is contained in:
@@ -64,6 +64,22 @@ there is no drift, and blocks the deployment (=exit 1=) if the
|
|||||||
realignment fails, so the problem is visible at deploy time instead
|
realignment fails, so the problem is visible at deploy time instead
|
||||||
of as a cryptic crash-loop.
|
of as a cryptic crash-loop.
|
||||||
|
|
||||||
|
* Datastore ownership alignment
|
||||||
|
|
||||||
|
The =init= hook aligns the ownership of the service datastore with
|
||||||
|
the user the Outline container runs as. Since 1.10.0 the image runs
|
||||||
|
as the unprivileged =nodejs= user (older images, up to 1.6.1, ran as
|
||||||
|
=root=), while the datastore is provisioned by =root=. Without
|
||||||
|
realignment the application cannot write its =uploads=, =public= and
|
||||||
|
=avatars= buckets and every attachment upload fails with "Permission
|
||||||
|
denied writing to ... Check the host machine file system
|
||||||
|
permissions". This was seen on 2026-09-11 on elabore.coop after the
|
||||||
|
1.6.1 to 1.10.0 upgrade, on every existing datastore.
|
||||||
|
|
||||||
|
The hook reads the user from the image's =Config.User=, so it stays
|
||||||
|
version-agnostic: images running as =root= are left untouched, and
|
||||||
|
re-running the hook on an already aligned datastore is a no-op.
|
||||||
|
|
||||||
* Building a new image
|
* Building a new image
|
||||||
|
|
||||||
We use the official image with an added patch due to 2 bugs:
|
We use the official image with an added patch due to 2 bugs:
|
||||||
|
|||||||
@@ -71,4 +71,42 @@ $SERVICE_NAME:
|
|||||||
#DEBUG: \"http\"
|
#DEBUG: \"http\"
|
||||||
"
|
"
|
||||||
|
|
||||||
|
## The datastore is bind-mounted into the container. Outline runs as
|
||||||
|
## an unprivileged user (image Config.User: root up to 1.6.1, "nodejs"
|
||||||
|
## since 1.10.0) and must write its uploads, public and avatars
|
||||||
|
## buckets. Provisioned by root, the datastore is not writable by
|
||||||
|
## that user and every upload fails with "Permission denied writing
|
||||||
|
## to ... Check the host machine file system permissions". Align the
|
||||||
|
## datastore ownership with the image user; skip images running as
|
||||||
|
## root. See README.org, "Datastore ownership alignment".
|
||||||
|
app_user=
|
||||||
|
if [ -n "$DOCKER_BASE_IMAGE" ]; then
|
||||||
|
app_user=$(docker image inspect "$DOCKER_BASE_IMAGE" \
|
||||||
|
--format '{{.Config.User}}') || exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$app_user" in
|
||||||
|
""|0|0:0|root)
|
||||||
|
## image runs as root: nothing to align
|
||||||
|
;;
|
||||||
|
*:*)
|
||||||
|
uid="${app_user%%:*}"
|
||||||
|
gid="${app_user#*:}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
uid_gid=($(docker_get_uid_gid "$SERVICE_NAME" "$app_user" "$app_user")) || exit 1
|
||||||
|
uid="${uid_gid[0]}"
|
||||||
|
gid="${uid_gid[1]}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "${uid:-}" ]; then
|
||||||
|
mkdir -p "$SERVICE_DATASTORE"
|
||||||
|
chown -R "$uid:$gid" "$SERVICE_DATASTORE" || {
|
||||||
|
err "Failed to align datastore ownership on '$uid:$gid'."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
info "Datastore ownership aligned on '$uid:$gid'."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user