@thankyoudom

Next Cloud

Building a self-hosted media hub: bulk migrating my entire iCloud photo library to Nextcloud using Docker, because digital hoarders need their own infrastructure.

placeholder

iCloud to Nextcloud Photo Migration Guide

Building a self-hosted media hub: bulk migrating my entire iCloud photo library to Nextcloud using Docker, because digital hoarders need their own infrastructure.


The Journey: Building a Personal Media Hub

As a self-proclaimed digital hoarder, I’ve accumulated thousands of photos scattered across various cloud services—primarily iCloud. Like many others, I became frustrated with storage limits, monthly fees, and lack of control over my own data. This led me down the path of building a personal media hub, essentially creating my own open-source alternative to Google Drive.

This guide documents one critical piece of that larger puzzle: migrating 7000+ photos from iCloud to a self-hosted Nextcloud instance. It’s a common stepping stone in homelab and cloud engineering projects, but getting Apple’s authentication to play nice with Linux Docker containers proved to be quite the adventure.

Why This Matters

The iCloud Problem: Apple’s web interface limits you to downloading 1000 photos at a time. For those of us with massive photo libraries, this becomes painfully tedious. You’d need to manually download, organize, and manage multiple batches—turning what should be a simple migration into a multi-day ordeal.

The Homelab Solution: By combining Docker, the open-source icloudpd tool, and Nextcloud, we can automate the entire process. Download all photos in one command, transfer them to your self-hosted cloud, and finally take full ownership of your digital memories.

This is part of the broader goal of digital sovereignty—owning your infrastructure, controlling your data, and never worrying about subscription fees or arbitrary storage limits again.


Prerequisites

  • Linux system (tested on Linux Mint 21.2)
  • Docker installed and running
  • Self-hosted Nextcloud instance (in Docker)
  • Apple ID with photos in iCloud

Step 1: Docker Setup

Install Docker

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
newgrp docker

Fix Docker DNS (Critical!)

Docker often has DNS resolution issues with Apple’s servers. This fix is essential:

sudo tee /etc/docker/daemon.json > /dev/null <<EOF
{
  "dns": ["8.8.8.8", "8.8.4.4", "1.1.1.1"]
}
EOF

sudo systemctl restart docker

Verify it works:

docker run --rm alpine ping -c 4 www.icloud.com

You should see successful ping responses, not “bad address” errors.


Step 2: Apple Authentication

Generate App-Specific Password

Apple requires app-specific passwords for third-party tools:

  1. Go to appleid.apple.com
  2. Navigate to: SecurityApp-Specific Passwords
  3. Click Generate an app-specific password
  4. Label it: “iCloudPD-Download”
  5. Copy the password (format: xxxx-xxxx-xxxx-xxxx)

Important: Delete any old app-specific passwords first, then use the new one immediately after generating.


Step 3: Download from iCloud

Prepare directories

mkdir -p ~/iCloudPhotos ~/.icloudpd-cookies
chmod 777 ~/.icloudpd-cookies

The chmod 777 is necessary because the Docker container needs write access to save authentication cookies.

Run the download

docker run -it --rm \
    --network host \
    -v ~/iCloudPhotos:/data \
    -v ~/.icloudpd-cookies:/cookies \
    icloudpd/icloudpd:latest \
    icloudpd \
    --username your-email@gmail.com \
    --password xxxx-xxxx-xxxx-xxxx \
    --directory /data \
    --cookie-directory /cookies

Replace your-email@gmail.com and xxxx-xxxx-xxxx-xxxx with your Apple ID and app-specific password.

Note: This will take several hours for 7000+ photos. The process can be interrupted and resumed—it tracks what’s already downloaded.


Step 4: Transfer to Nextcloud

Find your Nextcloud username

docker exec nextcloud-app-1 php occ user:list

Copy photos to Nextcloud

# Copy photos
sudo cp -r ~/iCloudPhotos /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/

# Fix permissions (Nextcloud runs as www-data, UID 33)
sudo chown -R 33:33 /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/iCloudPhotos/

# Tell Nextcloud to scan for new files
docker exec nextcloud-app-1 php occ files:scan YOUR-USERNAME

Replace YOUR-USERNAME with your actual Nextcloud username from the previous command.


Step 5: Flatten Folder Structure (Optional)

If your photos are scattered across many subfolders and you want them consolidated:

# Navigate to photos directory (requires sudo)
sudo -i
cd /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/YOUR-USERNAME/files/iCloudPhotos/

# Create Photos folder and move all images
mkdir -p Photos
find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.heic" \) -not -path "./Photos/*" -exec mv {} Photos/ \;

# Fix permissions
chown -R 33:33 Photos/

# Clean up empty directories
find . -type d -empty -delete

# Exit root shell
exit

# Rescan Nextcloud
docker exec nextcloud-app-1 php occ files:scan YOUR-USERNAME

This moves all image files from subdirectories into a single Photos folder for easier browsing.


Troubleshooting

“Cannot connect to Apple iCloud service”

Solution: Fix Docker DNS (Step 1). Verify with:

docker run --rm alpine ping -c 4 www.icloud.com

“Invalid email/password combination” (Code -20101)

Solutions:

  • Generate a fresh app-specific password
  • Delete ALL old app-specific passwords first
  • Use the new password immediately
  • Ensure you’re using the app-specific password, not your regular Apple ID password

“Permission denied” when writing cookies

Solution:

chmod 777 ~/.icloudpd-cookies

Authentication hangs at “Authenticating…”

Solutions:

  • Verify Docker DNS is working
  • Clear cookies: rm -rf ~/.icloudpd-cookies
  • Wait 30 minutes if you’ve had multiple failed attempts (Apple rate limiting)

Photos not appearing in Nextcloud

Solution:

docker exec nextcloud-app-1 php occ files:scan YOUR-USERNAME

Key Takeaways

The main challenges in this migration were:

  1. Docker DNS configuration - Critical for reaching Apple’s servers
  2. Cookie permissions - Need chmod 777 on the cookies directory
  3. App-specific password management - Delete old ones, use new ones immediately
  4. Nextcloud volume structure - Understanding Docker volume paths and permissions

Once these pieces fell into place, the process became straightforward and reliable.


What’s Next

This photo migration is just one piece of the larger personal media hub project. Next steps include:

  • Setting up automated backups
  • Implementing photo organization and tagging workflows
  • Integrating additional cloud services (Google Photos, Dropbox, etc.)
  • Building out a complete media server with Plex/Jellyfin

The journey from cloud dependence to digital sovereignty continues!


*Tested on: Linux Mint 21.2 Cinnamon Docker 24.x Nextcloud 27.x*