Docker Compose and PHP
Docker Compose and PHP

Solving Docker Compose Permissions Problems for Laravel: A Comprehensive Guide


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.

The Challenge: Understanding the Permissions Problem

Before delving into the solution, let’s gain a brief understanding of the issues and their root causes.

Docker Compose: Bridging the Gap in Data Handling

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.

Permissions Clash: The Heart of the Issue

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?

The Elusive Solution: Seeking Permanence

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.

The Solution: Replicating Container Permissions

To address the issue, we replicate the permissions of the files being added to the container inside the container itself.

Custom Dockerfile: Building the Foundation

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.

Commands for Dockerfile: Establishing Ownership

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.

Modifying PHP User: Achieving Compatibility

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.

Dynamic Environment Variables: Avoiding Hardcoding

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.

Leveraging Docker Compose: Passing Arguments

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.

Implementation: Putting It All Together

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.

Conclusion: Ensuring Compatibility Across Platforms

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 - 2024 Foreignerds. All Rights Reserved