How to Manage User and Group IDs for Correct File Permissions in the docker-icloudpd Container

Set the user_id and group_id variables in /config/icloudpd.conf to match your host user's UID and GID, and the container will automatically create a local Linux user and enforce ownership on all downloaded iCloud files.

The boredazfcuk/docker-icloudpd container creates a dedicated local user to own all downloaded photos and videos. By aligning this container-side user's UID and GID with your host system, you eliminate permission conflicts on bind-mounted volumes and ensure seamless read-write access from the host.

How the Container Handles User and Group IDs

The permission system relies on four core variables stored in /config/icloudpd.conf. On first start, init_config.sh populates this file with defaults, and on every subsequent start, launcher.sh reads these values to construct the container's user environment.

Configuration Variables

Variable Purpose Default Source
user Container-side username user Written by init_config.sh via write_variable user user
user_id UID for the container user 1000 Written by init_config.sh via write_variable user_id 1000
group Primary group name group Written by init_config.sh via write_variable group group
group_id GID for the primary group 1000 Written by init_config.sh via write_variable group_id 1000

User and Group Creation Process

During container initialization, launcher.sh executes a strict sequence to establish the runtime identity:

  1. Security Validation: The script explicitly forbids running as root inside the container. If user_id=0 or group_id=0 is detected, launcher.sh forces the value to 1000 and logs a warning.

  2. Group Creation: The create_group function initializes /etc/group and executes groupadd --gid "${group_id}" "${group}" to register the group with the specified GID.

  3. User Creation: The create_user function prepares /etc/passwd and runs useradd "${user}" --uid "${user_id}" --gid "${group_id}" to create the user with the configured UID mapped to the previously created group.

Permission Enforcement on Download Directories

After user creation, launcher.sh invokes permission-setting functions (such as set_owner_and_permissions_downloads) to ensure the download trees match the configured identity. The script walks download_path, jpeg_path, and video_path, executing chown and chmod operations:

find "${download_path}" ! -type l ! -user "${user_id}" -exec chown "${user_id}" {} +
find "${download_path}" -type d -exec chmod "${directory_permissions}" '{}' +
find "${download_path}" -type f -exec chmod "${file_permissions}" '{}' +

All files subsequently created by the iCloud downloader (/opt/icloudpd/bin/icloudpd) inherit this container-side UID/GID, which the host kernel interprets directly on bind-mounted volumes.

Step-by-Step Configuration Examples

Docker Run with Environment Variables

Pass the IDs as environment variables on the first run. The init_config.sh script captures these and persists them to /config/icloudpd.conf:

docker run -d \
  --name icloudpd \
  -e TZ=Europe/London \
  -e USER=user \
  -e USER_ID=1000 \
  -e GROUP=users \
  -e GROUP_ID=1000 \
  -v icloudpd_config:/config \
  -v /home/youruser/iCloud:/home/user/iCloud \
  boredazfcuk/icloudpd

Docker Compose Configuration

The repository provides an example compose file. Specify the IDs under the environment key:

version: "3.8"
services:
  icloudpd:
    image: boredazfcuk/icloudpd
    container_name: icloudpd
    environment:
      TZ: Europe/London
      USER_ID: 1000
      GROUP_ID: 1000
    volumes:
      - icloudpd_config:/config
      - /home/youruser/iCloud:/home/user/iCloud
    restart: unless-stopped

volumes:
  icloudpd_config:

Manual Configuration File Editing

If the container has already initialized, edit the configuration directly:


# Extract the config file, edit, and replace

docker cp icloudpd:/config/icloudpd.conf ./icloudpd.conf
cat > ./icloudpd.conf <<EOF
user=user
user_id=1000
group=group
group_id=1000
download_path=/home/user/iCloud
EOF
docker cp ./icloudpd.conf icloudpd:/config/icloudpd.conf
docker restart icloudpd

Verifying Permissions from the Host

After the container restarts, confirm the ownership aligns with your host user:

ls -ln /home/youruser/iCloud

You should see file ownership set to 1000 1000 (or whatever UID/GID you configured). If the IDs match your host user's /etc/passwd entry, you will have full read-write access without sudo.

Summary

  • The docker-icloudpd container creates a local Linux user inside the container to own all downloaded files.
  • UID and GID are controlled via the user_id and group_id variables in /config/icloudpd.conf.
  • The launcher.sh script enforces non-root IDs (rejecting 0), creates the user/group with useradd/groupadd, and recursively chowns the download directories.
  • Matching the container's UID/GID to the host user's IDs ensures seamless file access on bind-mounted volumes without permission errors.

Frequently Asked Questions

What happens if I set USER_ID or GROUP_ID to 0?

The container explicitly forbids running as root for security reasons. If launcher.sh detects user_id=0 or group_id=0 in the configuration, it forcibly rewrites the value to 1000 and logs a warning. This prevents the downloader from executing with elevated privileges inside the container.

Can I change the UID/GID after the container has already downloaded files?

Yes. Simply update the user_id and group_id values in /config/icloudpd.conf (either by editing the file directly or passing new environment variables if the config hasn't been persisted yet) and restart the container. The launcher.sh script will detect the change and recursively chown all files in the download, JPEG, and video directories to the new ownership.

How do I find my host user's UID and GID to match the container?

Run the id command on your host system:

id yourusername

The output will show uid=1000(yourusername) and gid=1000(yourgroupname). Use these numeric values for the USER_ID and GROUP_ID environment variables (or in icloudpd.conf) so the container creates files that your host user naturally owns.

Why does the container create a local user instead of using the host's user directly?

Docker containers run isolated from the host's user database. The container cannot directly reference host UIDs/GIDs by name, but the Linux kernel maps numeric IDs directly between container and host on bind-mounted volumes. By creating a local user with the same numeric UID/GID as the host user, the container ensures file ownership appears correct on both sides without requiring privileged access to the host's /etc/passwd.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →