Relationship Between Docker Container and Host Machine Users

Introduction⌗
Recently, I discovered that a PHP project in a Docker container was showing permission errors when trying to write logs. Looking at the permissions of the storage directory in the project, I found:
ll
total 8.0K
drwxr-xr-x 4 www-data www-data 4.0K Feb 7 2021 public
drwxr-xr-x 7 www-data www-data 4.0K Feb 7 2021 storage
Investigation⌗
In the PHP-FPM container, both the user and group being used were www-data, which explained why writing was not possible with 755 permissions.
I then tried creating a www-data user and group on the host machine and changing the owner and group of the project’s storage directory to www-data.
However, after restarting PHP-FPM, I still couldn’t write to the storage directory. Why was this happening when the user and group in the container matched those on the host?
After some investigation and search-engine-oriented programming, I discovered that the issue was likely related to the UID and GID.
On the host machine, the www-data UID and GID were 1001 and 1002 respectively (because GID 1001 was already in use), while in the PHP-FPM container, the www-data UID and GID were both 1000.
Confirming the Theory⌗
To confirm this theory, I consulted Linux documentation. Indeed, Linux uses UIDs as the basis for permission checks, not usernames.
Now that I had identified the problem, the solution was simple: manually modify the user and group IDs of www-data in the PHP-FPM container to match those on the host machine.
groupmod -o -g 1002 www-data
usermod -o -u 1001 -g www-data www-data
This is because on my host machine, the www-data user has ID 1001, and the www-data group has ID 1002.
With these commands, I could modify the user and group IDs in the container to match the system. After restarting the PHP-FPM container and testing again, I found that writing to storage now worked correctly.
Questions⌗
Although we can configure which user and group to use when starting services in Dockerfile and Docker Compose, this heavily relies on convention. For example, the problem I encountered was because my host system didn’t have a www-data user and group.
This led to the permission issues mentioned earlier. While Docker Compose can specify a user (as can docker run), for services like PHP-FPM, this setting isn’t very meaningful because the writing is done by worker processes forked from the master process.
These worker processes use the user and group defined in the PHP-FPM configuration file, which by default is www-data, with predetermined UID and GID.
So here’s the issue: a UID 1000 and GID 1000 defined on Server A might not be usable on Server B. We can only rebuild the image on different servers and modify the UID and GID in the container during the build to match the system environment.
My Solution⌗
# Configure non-root user.
ARG PUID=1000
ENV PUID ${PUID}
ARG PGID=1000
ENV PGID ${PGID}
RUN groupmod -o -g ${PGID} www-data; \
usermod -o -u ${PUID} -g www-data www-data
This ensures that the user ID in the host machine matches that in the container. Before building the image, if the user and group don’t exist on the host machine, you’ll need to create them manually with the following command:
sudo useradd \
--user-group \
--no-create-home \
--shell /sbin/nologin \
--comment "HTTP web service user" \
www-data
sudo id www-data
(x)uid=1001(www-data) gid=1002(www-data) groups=1002(www-data)
Take the UID and GID from the output of sudo id www-data
and write them into the environment variables in Docker Compose, then build and start the container.
For those who don’t want to rebuild the image, you can directly use the groupmod and usermod commands in the container to modify the UID and GID of the username to match the host machine.
I hope this is helpful, Happy hacking…