You can nudge your life in a new direction every day.

Create a local Laravel dev environment with Docker

Submitted by admin on Tue, 04/20/2021 - 09:19
UnexpectedValueException
The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission denied

 

 

We can see the apache webserver process is own by www-data

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    1 root      20   0  104796  32956  24820 S   0.0   0.1   0:00.06 apache2
   17 www-data  20   0  113528  25284   8468 S   0.0   0.1   0:00.06 apache2
   18 www-data  20   0  104844   9984   1836 S   0.0   0.0   0:00.00 apache2
   19 www-data  20   0  104828   9984   1836 S   0.0   0.0   0:00.00 apache2
   20 www-data  20   0  104828   9984   1836 S   0.0   0.0   0:00.00 apache2
   21 www-data  20   0  104828   9984   1836 S   0.0   0.0   0:00.00 apache2

however, the file permissions are mirrored for your local machine by the attached Docker volume and owned by user 1000.

drwxr-xr-x  3 1000 1000 4096 Mar 23 17:25 app
drwxr-xr-x  6 1000 1000 4096 Mar 23 17:25 framework
drwxr-xr-x  2 1000 1000 4096 Mar 23 17:25 logs

 

You can resolve this by simply changing the permissions for the directory locally or in the container; however the idea here is to automate the local environment and this is an unnecessary additional step.

chmod -R 777 /var/www/html/storage

 I will jump to a more viable solution and then explain why. In the following Dockerfile, these three lines are most important:

RUN useradd -u 1000 local

RUN  sed -i 's!APACHE_RUN_USER:=www-data!APACHE_RUN_USER:=local!g' /etc/apache2/envvars
RUN  sed -i 's!APACHE_RUN_GROUP:=www-data!APACHE_RUN_GROUP:=local!g' /etc/apache2/envvars

What we are doing here is adding a new user to the Docker container that matches the user id of my local machine, 1000.

We are then overwriting Apache's user and group environment variables, However, at least this Apache / Linux setup, doesn't allow for uids so you have to use a username.

FROM php:7.4-apache
RUN useradd -u 1000 local
RUN set -ex; \
        \
        savedAptMark="$(apt-mark showmanual)"; \
        \
        apt-get update; \
        apt-get install -y --no-install-recommends \
                libfreetype6-dev \
                libjpeg-dev \
                libmagickwand-dev \
                libpng-dev \
                libzip-dev \
        ; \
        \
        docker-php-ext-configure gd \
                --with-freetype \
                --with-jpeg \
        ; \
        docker-php-ext-install -j "$(nproc)" \
                bcmath \
                exif \
                gd \
                mysqli \
                zip \
        ; \
        pecl install imagick-3.4.4; \
        docker-php-ext-enable imagick;

RUN set -eux; \
        a2enmod rewrite expires;

    # Laravel's index.php in in public.
RUN  sed -i 's!APACHE_RUN_USER:=www-data!APACHE_RUN_USER:=local!g' /etc/apache2/envvars
RUN  sed -i 's!APACHE_RUN_GROUP:=www-data!APACHE_RUN_GROUP:=local!g' /etc/apache2/envvars
RUN  sed -i 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/000-default.conf

CMD ["apache2-foreground"]

So this should work, but only if your local machine is writing files as uid 1000.

I will look to make this more generic later