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.

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:
- Go to appleid.apple.com
- Navigate to: Security → App-Specific Passwords
- Click Generate an app-specific password
- Label it: “iCloudPD-Download”
- 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:
- Docker DNS configuration - Critical for reaching Apple’s servers
- Cookie permissions - Need
chmod 777on the cookies directory - App-specific password management - Delete old ones, use new ones immediately
- 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* |