Laravel app: permission denied to write on mounted volume

8 months ago

I am using serversideup/php:8.3-unit as docker image in my application. The home directory of my application is /var/www/html/ and I am mounting the volume to /var/www/html/storage/app/public which is where the files that are uploaded to my application are stored.

I already set the environment variable RAILWAY_RUN_UID=0 but I have permission issues to write to the mounted volume.

The container is running as a non-privileged user www-data but i still have the following error:

[2024-08-22 15:57:00] production.ERROR: file_put_contents(/var/www/html/storage/app/public/hello.txt): Failed to open stream: Permission denied {"userId":1,"exception":"[object] (ErrorException(code: 0): file_put_contents(/var/www/html/storage/app/public/storage/hello.txt): Failed to open stream: Permission denied at /var/www/html/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:204)

This is the code that generates the error:

Route::get('/example', function () {
    File::put('/var/www/html/storage/app/public/hello.txt', now()->toDateTimeString());

    return File::get('/var/www/html/storage/app/public/hello.txt');
});

0 Replies

8 months ago

e2d6c1c6-c741-45c3-b553-98603eaddb38


8 months ago

Hey, can you send your dockerfile?


8 months ago

FROM serversideup/php:8.3-unit

USER root

# Install server dependencies
RUN apt-get update \
    && apt-get install -y ca-certificates gnupg \
    && mkdir -p /etc/apt/keyrings \
    && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
    && apt-get update \
    && apt-get install -y --no-install-recommends nodejs \
    && install-php-extensions intl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

# Install project dependencies
COPY package*.json composer.* ./
RUN composer install --no-dev --no-autoloader --no-scripts --no-interaction && npm ci

COPY . .

RUN composer dump --no-interaction && \
    npm run build && \
    rm -rf node_modules && \
    # find /var/www/html -type d -not -path "./vendor/*" -not -path "./.git/*" -exec chmod 755 "{}" \; && \
    # find /var/www/html -type f -not -path "./vendor/*" -not -path "./.git/*" -exec chmod 644 "{}" \; && \
    chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache && \
    php /var/www/html/artisan filament:optimize

USER www-data

8 months ago

can you try without switching back to the non root user?


8 months ago

Yes, trying…


8 months ago

Same problem.


8 months ago

Can i specify RAILWAYRUNUID=33 to make it the same uid as the image?


8 months ago

1276211853365874700


8 months ago

nope, the volume is mounted as root, you would need to chown the volume mount before starting your app


8 months ago

like what is done here -


8 months ago

The problem has been solved, I will share my solution.


8 months ago

Because I'm using a docker image that by default runs as a non-privileged user www-data:www-data or 33:33, it's necessary to change the owner of the mounted volume after starting the container.

To achieve this, I added a script in /etc/entrypoint.d/99-starting-hook.sh with the following content:

#!/bin/sh

# chown the mount to allow the www-data user read and write access.
chown -R 33:33 /var/www/html/storage/app/public && echo "✅ added permissions to mounted volume"

# optimize filament for production (optional).
php /var/www/html/artisan filament:optimize

This is my final Dockerfile:

FROM serversideup/php:8.3-unit

USER root

# Install server dependencies
RUN apt-get update \
    && apt-get install -y ca-certificates gnupg \
    && mkdir -p /etc/apt/keyrings \
    && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
    && echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \
    && apt-get update \
    && apt-get install -y --no-install-recommends nodejs \
    && install-php-extensions intl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/*

COPY --chmod=755 ./99-starting-hook.sh /etc/entrypoint.d/99-starting-hook.sh

USER www-data

COPY --chown=www-data:www-data . .

RUN composer install --no-dev --no-interaction && \
    npm ci && \
    npm run build && \
    rm -rf node_modules/ && \
    chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache /var/www/html/public

There is no need to add the RAILWAY_RUN_UID=0 environment variable because the volume is already owned by the www-data user.

If you are using serversideup/php:8.3-unit you must add the following environment variable:

AUTORUN_ENABLED=true

This will run php artisan storage:link after starting the container.


8 months ago

perfect, glad i could help!


Laravel app: permission denied to write on mounted volume - Railway Help Station