Laravel app: permission denied to write on mounted volume

10 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

10 months ago

e2d6c1c6-c741-45c3-b553-98603eaddb38


10 months ago

Hey, can you send your dockerfile?


10 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

10 months ago

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


10 months ago

Yes, trying…


10 months ago

Same problem.


10 months ago

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


10 months ago

1276211853365874700


10 months ago

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


10 months ago

like what is done here -


10 months ago

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


10 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.


10 months ago

perfect, glad i could help!


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