Docker Permission Issues: Why chmod Commands in Dockerfile Don’t Work for Apache in Symfony Apps


1 views

When working with Symfony applications in Docker containers, a particularly puzzling issue occurs where chmod commands in the Dockerfile appear to set permissions correctly (as verified by ls -a), yet Apache still throws permission denied errors. Only when running the same chmod commands manually inside the container does the issue resolve.

The core issue stems from how Docker handles volume permissions during the build phase versus runtime. The permissions set during build time don't properly account for:

  • The UID/GID mapping between host and container
  • Apache's default user (www-data) permissions
  • Docker's layer caching behavior

Here are several approaches that actually work:

1. Using the Correct User During Build

# Dockerfile solution
FROM php:7-apache

# Set the correct user before permission changes
ARG userid=33
ARG groupid=33

RUN usermod -u ${userid} www-data && \
    groupmod -g ${groupid} www-data

# ... rest of your Dockerfile ...

# Run chmod as www-data user
USER www-data
RUN find /var/www/html/ -type d -exec chmod 755 {} \; && \
    find /var/www/html/ -type f -exec chmod 644 {} \; && \
    chmod -R 777 /var/www/html/app/cache /var/www/html/app/logs

USER root

2. Entrypoint Script Solution

Create an entrypoint.sh:

#!/bin/bash
set -e

# Fix permissions
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
chmod -R 777 /var/www/html/app/cache
chmod -R 777 /var/www/html/app/logs

# Start Apache
exec apache2-foreground

Then update your Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

3. Docker Compose Solution

If using Docker Compose, you can set user permissions at runtime:

version: '3'
services:
  app:
    build: .
    user: "33:33"
    volumes:
      - ./:/var/www/html
  • Always set permissions as late as possible in your container lifecycle
  • Consider using named volumes instead of host mounts for production
  • For development, the entrypoint script approach is most reliable
  • Test permissions thoroughly before deploying to production

Many developers encounter this puzzling scenario where chmod commands in Dockerfiles appear to execute successfully, yet the containerized application (especially web servers like Apache) still throws permission errors. What makes this particularly frustrating is that manually running the same chmod commands inside the container fixes the issue immediately.

The core issue lies in how Docker handles volume permissions during the build process versus runtime. When you run chmod in the Dockerfile, it affects the base image layers, but these permissions can be overridden when:

  • Volume mounts are used (even anonymous ones)
  • The host filesystem permissions interfere
  • User namespace remapping is enabled
  • The container runs with different UID/GID than during build

Here's an improved Dockerfile approach that addresses the permission issues:

FROM php:7-apache

# Set the user/group explicitly
ARG USER_ID=33
ARG GROUP_ID=33

RUN apt-get update && \\
    apt-get install -y libicu-dev freetds-common freetds-bin unixodbc && \\
    docker-php-ext-install intl mbstring && \\
    a2enmod rewrite

# Create the www-data user with specific UID/GID to match host
RUN usermod -u ${USER_ID} www-data && \\
    groupmod -g ${GROUP_ID} www-data

COPY app/php.ini /usr/local/etc/php/
COPY app/apache2.conf /etc/apache2/apache2.conf

# Copy files with correct ownership
COPY --chown=www-data:www-data ./ /var/www/html

# Set permissions as www-data user
USER www-data
RUN find /var/www/html/ -type d -exec chmod 755 {} \\; && \\
    find /var/www/html/ -type f -exec chmod 644 {} \\; && \\
    chmod -R 777 /var/www/html/app/cache /var/www/html/app/logs

# Switch back to root for Apache to run properly
USER root

If the above solution doesn't fully resolve your issue, consider these additional methods:

1. Entrypoint Script Solution

#!/bin/bash
chown -R www-data:www-data /var/www/html/app/cache
chown -R www-data:www-data /var/www/html/app/logs
exec apache2-foreground

Add to your Dockerfile:

COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]

2. Using the correct build context

Ensure your build context includes all necessary files with proper permissions on the host first:

chmod -R 755 ./app/cache
chmod -R 755 ./app/logs
docker build -t myapp .

When troubleshooting, these commands are invaluable:

# Check current user in container
docker exec -it container_id whoami

# Inspect file permissions
docker exec -it container_id ls -la /var/www/html/app/cache

# Check process ownership
docker exec -it container_id ps aux