Introduction
Over the past year, I’ve dedicated my efforts to maintain and improve a fundamental Docker Compose setup for Laravel. Originally designed for local development, this setup has served its purpose well. However, its release led to numerous concerns and GitHub issues related to permissions problems from users. After extensive experimentation, I have finally discovered a robust solution that addresses these issues across various platforms and operating systems, both locally and in production. In this article, we will explore the challenges and delve into the solution.
Before delving into the solution, let’s gain a brief understanding of the issues and their root causes.
Docker offers two primary methods for importing data into a container: ADD/COPY commands in Dockerfiles and volumes. Each method has its advantages and drawbacks, impacting how your application interacts with the local file system during development.
The crux of the problem lies in the mismatch of ownership and permissions between the host system and the Docker container. This incongruence causes conflicts when attempting to modify files within the application’s directory. But why does this happen when Docker containers are supposed to be isolated systems?
Manually modifying permissions within the container or adding commands to the Dockerfile are temporary fixes, as permissions reset when containers are restarted. We need a solution that is both dependable and replicable.
To address the issue, we replicate the permissions of the files being added to the container inside the container itself.
We create a custom Dockerfile for the PHP containers based on the php-fpm-alpine image. Within this Dockerfile, we establish a group called “laravel” and a corresponding user, “laravel,” with the same group ID as the host machine’s group that owns the application’s files.
We use the following commands within the Dockerfile to set up the laravel group and user:
RUN addgroup -g ${GID} --system laravel
RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel
These commands ensure that the user and group inside the container match the ownership of the app’s files on the host system.
By altering the user that PHP runs as within the container, we ensure that PHP processes use the newly created “laravel” user. We achieve this with the following commands within the Dockerfile:
RUN sed -i "s/user = www-data/user = laravel/g" /usr/local/etc/php-fpm.d/www.conf
RUN sed -i "s/group = www-data/group = laravel/g" /usr/local/etc/php-fpm.d/www.conf
These commands replace the default user and group used by PHP with the “laravel” user and group, mirroring the ownership of the app’s files.
Rather than hardcoding specific values, we employ environment variables as arguments within the Dockerfile. These environment variables, UID and GID, are determined based on the user’s ID and group’s ID on the host system. This dynamic approach ensures adaptability.
We integrate these dynamic environment variables into the docker-compose.yml file using arguments:
This configuration allows users to set their own UID and GID or fallback to default values.
To implement the solution, users must check if the environment variables UID and GID exist by running echo $UID
and echo $GID
. If they don’t exist, they can be exported from the host system using the following command:
With these environment variables set, users can build and start their containers as usual with:
The PHP container will be built, creating a “laravel” group and user with the user’s ID and group’s ID. PHP processes will use the “laravel” user, ensuring proper write access to the app’s filesystem.
Permissions in Docker and PHP can be complex, and various operating systems and platforms may exhibit different behaviors. Extensive testing across major environments, both for local development and production, has shown that this solution effectively mitigates permissions issues. However, it’s essential to note that using a non-root sudo user for production systems is recommended, and additional guidance is provided in the README of the associated GitHub repository for users following that path.
In summary, resolving Docker Compose permissions problems for Laravel requires a combination of thoughtful Dockerfile configuration, dynamic environment variables, and Docker Compose integration. By replicating container permissions to match the host system, we ensure seamless development and production workflows across a range of platforms and operating systems.
© 2013 - 2025 Foreignerds. All Rights Reserved