fix(docker): recreate storage directories and guard the chown (#705)

Backport of InvoiceShelf/InvoiceShelf#702 to 2.x. The chown half of it is
a 2.x-only fix — 3.x had already dropped that line.

storage/framework/{cache,sessions,views}, storage/logs and storage/app
hold no tracked content, only .gitignore stubs, so nothing guarantees they
exist inside a mounted volume. Docker seeds a named volume from the image
once, when it is empty, and never again — a volume created by an older
image keeps whatever it had through every upgrade. Without those
directories Laravel cannot boot and the sqlite branch cannot place its
database.

The unguarded `chown -R www-data:www-data storage` was worse than
ineffective. The image runs as www-data (uid 82), so chown of any file it
does not own returns EPERM, and under `set -e` that aborts the entrypoint.
A single uploaded file owned by the host user is enough to stop the
container from starting — on exactly the mounted-volume setups the chown
was meant to help. Verified against a built image: entrypoint exits 1
before this change, 0 after.

A mount the container genuinely cannot write to is not something the
entrypoint can repair, so it now says what is wrong and names the remedy
instead of failing later with `cp: can't create ...`.
This commit is contained in:
Darko Gjorgjijoski
2026-07-29 12:36:56 +02:00
committed by GitHub
parent 78b2e35a2e
commit 6c8b7d4dde
+36 -2
View File
@@ -12,6 +12,32 @@ InvoiceShelf Version: $version
cd /var/www/html
# These carry no tracked content — only .gitignore stubs — so a mount over
# storage/ can arrive without them, and Laravel then dies at boot with "Please
# provide a valid cache path" (the compiled view path is resolved with
# realpath(), which returns false for a missing directory). Recreate them before
# anything writes there, including the sqlite database placed in storage/app
# below. See InvoiceShelf/docker#75, #69 and #77.
echo "**** Ensuring storage directories exist ****"
if ! mkdir -p \
storage/app/public \
storage/framework/cache/data \
storage/framework/sessions \
storage/framework/views \
storage/logs \
bootstrap/cache 2>/dev/null; then
echo "!!!! Cannot write to /var/www/html/storage."
echo "!!!! This container runs as uid $(id -u) (www-data), but the mounted"
echo "!!!! directory belongs to someone else — usually a bind mount pointing"
echo "!!!! at a host directory owned by your own user."
echo "!!!! Give that directory to uid 82 on the host and start again:"
echo "!!!!"
echo "!!!! sudo chown -R 82:82 /path/to/your/storage"
echo "!!!!"
echo "!!!! See https://github.com/InvoiceShelf/docker/issues/77"
exit 1
fi
if [ ! -e /var/www/html/.env ]; then
cp .env.example .env
echo "**** Setup initial .env values ****" && \
@@ -35,8 +61,16 @@ fi
echo "**** Setting up folder permissions ****"
chmod +x artisan
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
# Only root may change ownership. The image runs as www-data, where chown of a
# foreign-owned file is EPERM — and under `set -e` that stopped the container
# from starting at all, on exactly the mounted-volume setups this was meant to
# help. Skip it there rather than fail the boot; still applied when running as
# root. See InvoiceShelf/docker#77 and #69.
if [ "$(id -u)" = "0" ]; then
chown -R www-data:www-data storage bootstrap/cache
chmod -R 775 storage bootstrap/cache
fi
if [ ! -L /var/www/html/public/storage ]; then
echo "**** Creating storage symlink (public/storage) ****"