If you run a web application behind an Nginx reverse proxy with Apache handling your backend inside a Docker container, you might hit a frustrating permission barrier: your website cannot upload files unless you set the upload directory permissions to 777.
While setting 777 permissions technically solves the issue, it creates a massive security vulnerability by allowing any user on the system to read, write, and execute files in that folder. Ideally, upload directories should be restricted to 755 (or 775). Here is why this happens and how to fix it properly.
The Root Cause: UID/GID Mismatch
This issue occurs due to a User ID (UID) mismatch between your host machine operating system and the Apache web process running inside the Docker container.
In standard Docker images (such as official httpd or php:apache builds), Apache runs under an unprivileged user—typically www-data (UID 33) or apache (UID 48). However, when your public_html or upload folder is mounted from the host system, it is usually owned by your host user (e.g., UID 1000).
When Apache tries to save an uploaded file into a directory with 755 permissions:
- Owner permissions (7 –
rwx): Applies only to UID1000(Host user). - Group permissions (5 –
r-x): Applies to the group assigned to the folder. - Others permissions (5 –
r-x): Applies to Apache running inside the container.
Because Apache falls under “Others”, it only gets read and execute rights. It lacks write permission, causing file uploads to fail unless you grant write access to everyone via 777.
Step-by-Step Solution: Fixing Ownership for 755 Permissions
Step 1: Identify Apache’s User ID inside Docker
Run the following command to check which user Apache is using inside your active container:
docker exec -it <container_name> id www-data
# Or for Alpine-based / httpd images:
docker exec -it <container_name> id apache
(In most official PHP/Apache images, www-data has UID 33 and GID 33.)
Step 2: Transfer Ownership to the Apache User
You can adjust the ownership of your upload directory in one of two ways:
Option A: From Inside the Container (Recommended)
docker exec -it <container_name> chown -R www-data:www-data /var/www/html/path/to/upload
Option B: Directly on the Host Machine
If the directory is bind-mounted from your host system, set the numerical UID/GID 33:33 directly on the host folder:
sudo chown -R 33:33 /path/to/public_html/upload
Step 3: Apply Secure 755 Permissions
Now that Apache owns the directory, you can safely enforce strict permissions without breaking file uploads:
# Set upload folder permissions to 755
sudo chmod 755 /path/to/public_html/upload
# Ensure existing uploaded files inside have 644 permissions
sudo find /path/to/public_html/upload -type f -exec chmod 644 {} +
Alternative: Share Ownership with Host User (775 Permissions)
If your host user needs direct read/write access to edit uploaded files, set the group ownership to 33 and use 775 permissions instead:
sudo chown -R $USER:33 /path/to/public_html/upload
sudo chmod -R 775 /path/to/public_html/upload
Summary
Never rely on 777 permissions in production environments. By transferring folder ownership to Apache’s UID (33 / www-data), your web application can seamlessly process file uploads while keeping your file system secure with standard 755 permissions.