Docker Container Define user home folder
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Mastering Container Permissions: Defining User Home Folders in Docker
As senior developers working with containerized applications, managing file system permissions and user contexts within Docker containers is a frequent source of frustration. We often encounter scenarios where an application runs fine when executed by root, but fails mysteriously when dropped into a non-root environment, especially when dealing with Composer, Artisan commands, or configuration writing.
This post dives into a specific, common pain point revealed by your provided setup—how to correctly define and manage the home directory for users inside a Docker container to avoid permission errors like the one you encountered during php artisan tinker.
The Problem: Missing Home Directory Context
You've observed a classic permissions deadlock. When running commands inside a container, especially those executed as a specific user (like php in your setup), the operating system expects that user to have a valid home directory (/home/<user>) where configuration files and caches can be written.
Your symptoms clearly point to this issue:
whoamifailing suggests the mapped UID/GID isn't recognized by the container environment for a standard home path.ls ~failing confirms that the expected home directory does not exist inside the container filesystem.- The resulting application error (
Writing to directory /.config/psysh is not allowed) occurs because the process lacks the necessary permissions or the parent directory structure is fundamentally broken, preventing writes to configuration paths.
This issue often arises when relying solely on volume mounts without explicitly managing the internal user setup within the Docker image itself.
The Solution: Explicitly Defining User Structure in the Dockerfile
The solution lies not just in docker-compose.yml, but primarily in ensuring the base image is configured to support the user context you are trying to establish. We need to explicitly create the necessary directories and set ownership within the build process.
For services like PHP, which often execute commands as a specific user (e.g., www-data or a mapped UID), we must use the USER instruction carefully combined with directory creation.
Step 1: Refine Your Dockerfile for User Setup
Instead of relying on external variables to magically create directories, we should manage the user setup directly inside the PHP image build process. This ensures consistency regardless of the host environment's UID/GID mapping.
Here is how you can modify your Dockerfile-php to establish a safe working context:
FROM php:8.0-fpm
# Install dependencies (as you already have)
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions gd zip pdo_mysql
COPY --from=composer /usr/bin/composer /usr/bin/composer
# --- THE FIX: Set up the user and home directory ---
# Create a non-root user (e.g., 'appuser') and set ownership for volume mounts
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
RUN chown -R appuser:appgroup /var/www/html
# Switch to the new user for subsequent commands and application execution
USER appuser
WORKDIR /var/www/html
# Ensure necessary directories are writable if needed (though /var/www/html is usually sufficient)
# If you need a specific home directory structure:
# RUN mkdir -p /home/appuser && chown appuser:appuser /home/appuser
# Your application setup commands follow...
Step 2: Adjusting docker-compose.yml for Consistency
By setting the user inside the Dockerfile, we can simplify and make the user: directive in your docker-compose.yml more robust. Since we are now operating as a known internal user (appuser), we can often remove the reliance on mapping host UID/GID directly if necessary, or ensure that the volume permissions align with the container's defined ownership.
In your case, since you used ${HOST_UID}:${HOST_GID}, this is generally correct for volume mounting. The key change is ensuring that the application itself runs under a user that owns the mounted volumes. By setting USER appuser in the Dockerfile, subsequent commands executed by docker-compose exec will inherit these permissions correctly because the files are owned by appuser.
Conclusion: Building Resilient Laravel Deployments
Managing container file system interactions is fundamental to building resilient applications, particularly within frameworks like Laravel. When deploying complex services, especially those involving Composer dependencies and configuration writing (as seen in your Artisan example), treating the container environment as a self-contained unit—rather than just a generic execution sandbox—is crucial.
By explicitly defining users and ownership within the Dockerfile, you move from reactive debugging (fixing permission errors after they occur) to proactive development (building an environment where permissions are guaranteed). This practice ensures that your Laravel application, whether running migrations or utilizing Composer caches, operates smoothly and predictably across different deployment environments. For robust setups, always aim for explicit ownership management when dealing with mounted volumes and user execution.