Privacy-Focused Photo Storage Solutions
Google Photos and Apple iCloud analyze every photo you upload — detecting faces, locations, objects, and content. This analysis powers their search features, but also creates detailed behavioral profiles. Alternatives range from self-hosted solutions you run yourself to zero-knowledge cloud options where the provider can’t read your photos.
What Photo Services Analyze
Google Photos:
- Face recognition (links faces across your photos to known people)
- Object detection (cars, food, animals, scenes)
- Location metadata extraction
- OCR (reads text in photos)
- Content moderation scanning (federal legal requirement for CSAM; Google also scans for policy violations)
- Results tied to your Google account for advertising
Google’s face recognition clusters photos of the same person and links them to contacts in your address book. This analysis runs server-side on uploaded originals. Google’s privacy policy allows them to use your content to improve their AI models on the free plan.
Apple iCloud:
- On-device face recognition (Memories, People albums — stays on device)
- CSAM scanning was proposed (paused indefinitely after backlash)
- Advanced Data Protection (opt-in E2EE) encrypts photos so Apple can’t see them
- Without Advanced Data Protection: Apple holds encryption keys
Apple’s differentiation is that most AI analysis happens on-device rather than in the cloud. However, without Advanced Data Protection enabled, Apple has the technical ability to access your iCloud photos. Law enforcement requests to Apple are far more common than requests to Ente or self-hosted providers.
Amazon Photos (with Prime):
- Face recognition for People album
- Object detection for search
- Amazon may use photos to improve Alexa visual features
Option 1: Self-Hosted — Immich
Immich is the most actively developed self-hosted Google Photos alternative. Face recognition, map view, timeline, mobile backup — feature parity with Google Photos without the surveillance. The project has grown from a side project to a dedicated team with over 40,000 GitHub stars as of 2026.
# Install Immich via Docker Compose
mkdir -p ~/immich && cd ~/immich
curl -L https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml -o docker-compose.yml
curl -L https://github.com/immich-app/immich/releases/latest/download/example.env -o .env
# Edit .env with your settings:
nano .env
# .env
UPLOAD_LOCATION=./library # Where photos are stored on disk
DB_PASSWORD=your_db_password
IMMICH_VERSION=release
# Start Immich
docker compose up -d
# Check all services are running
docker compose ps
# Access: http://your-server:2283
# Create admin account on first login
# Set up mobile app: immich.app → download iOS/Android client
# Enter server address → log in → enable automatic backup
Immich features:
- Local face recognition (runs on your server using the InsightFace model, not cloud)
- Machine learning object tagging (CLIP embeddings for natural language search)
- Shared albums with external link sharing
- Map view using photo GPS metadata
- External library support (points Immich at an existing photo folder without moving files)
- Partner sharing (share libraries between multiple Immich accounts)
- Duplicate detection
The machine learning features in Immich run on the immich-machine-learning container using your server’s CPU or GPU. On a modest server (4-core, 8GB RAM), initial indexing of 50,000 photos takes several hours in the background. After that, new photos are indexed within minutes of upload.
Expose Immich Securely
# Never expose Immich directly — use a reverse proxy with TLS
# Nginx config:
server {
listen 443 ssl;
server_name photos.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/photos.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photos.yourdomain.com/privkey.pem;
client_max_body_size 50000M;
proxy_read_timeout 600s;
location / {
proxy_pass http://127.0.0.1:2283;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Use Certbot to obtain a free Let’s Encrypt TLS certificate:
sudo certbot --nginx -d photos.yourdomain.com
If you don’t want a public DNS record, run Immich over Tailscale — assign a Tailscale IP to your server and access it via https://server-name.tailnet-name.ts.net:2283 from any Tailscale device without exposing a port to the internet.
Option 2: Self-Hosted — PhotoPrism
PhotoPrism is more privacy-conservative in its AI features — you control which analysis runs. It’s optimized for browsing large libraries and works well as a read-heavy archive viewer rather than a live backup target.
# Install PhotoPrism via Docker
mkdir -p ~/photoprism/storage ~/photoprism/originals
cat > ~/photoprism/docker-compose.yml << 'EOF'
version: '3.5'
services:
photoprism:
image: photoprism/photoprism:latest
restart: unless-stopped
ports:
- "2342:2342"
environment:
PHOTOPRISM_AUTH_MODE: "password"
PHOTOPRISM_ADMIN_PASSWORD: "StrongPassword!"
PHOTOPRISM_SITE_URL: "https://photos.yourdomain.com/"
PHOTOPRISM_ORIGINALS_LIMIT: 5000 # MB per upload
PHOTOPRISM_DETECT_NSFW: "false"
PHOTOPRISM_UPLOAD_NSFW: "true"
# Disable AI features for maximum privacy:
PHOTOPRISM_DISABLE_TENSORFLOW: "false" # set true to disable all ML
PHOTOPRISM_DISABLE_FACES: "false"
volumes:
- "~/photoprism/originals:/photoprism/originals"
- "~/photoprism/storage:/photoprism/storage"
EOF
docker compose up -d
PhotoPrism works well with existing file structures — point it at directories organized by year/month and it indexes them without moving anything. This is useful if you have years of photos already on disk and want browsing capabilities without restructuring.
PhotoPrism requires a MariaDB or SQLite database for its index. For large libraries (100,000+ photos), MariaDB performs substantially better. Run photoprism index from the container shell to re-index after adding files manually.
Option 3: Ente Photos (Zero-Knowledge Cloud)
Ente Photos is a cloud service with zero-knowledge encryption — your photos are encrypted on your device before upload. Ente cannot see your photos, and this is verifiable because the client is open source (github.com/ente-io/ente).
# Ente Photos: ente.io
# Plans from $2/month for 50GB
# Android/iOS: download from app stores
# Desktop: available for Linux, macOS, Windows
# The key difference from Google Photos:
# - Photos encrypted with your master key before upload
# - Ente holds only ciphertext
# - Face recognition runs on-device (not on Ente's servers)
# CLI tool for bulk operations:
npm install -g @ente/cli
# Configure
ente config set email you@example.com
ente auth
# Upload a folder
ente upload /path/to/photos "Album Name"
# Download / export
ente download --album "Album Name" /local/path
Ente’s encryption uses libsodium (ChaCha20-Poly1305 for content, XSalsa20-Poly1305 for key derivation). The master key is derived from your password client-side using Argon2 — Ente’s servers never see the password or the master key.
Trade-off: Ente lacks advanced search and organization features compared to Google Photos. No object search or automatic location tagging (these would require server-side analysis). The mobile app is well-polished and supports automatic backup from camera roll. The desktop app and CLI are suitable for bulk uploads from existing photo libraries.
Ente also offers an open-source self-hosted backend (ente-server) with your own storage, but the server setup is complex. For most users, Ente’s paid cloud is the practical choice.
Option 4: Encrypted Sync with Cryptomator
Keep photos in any cloud provider (Dropbox, S3, Backblaze) but encrypt them first:
# Cryptomator creates an encrypted vault
# Photos go in vault → encrypted → uploaded to cloud provider
# Install Cryptomator
# Download from cryptomator.org or:
flatpak install org.cryptomator.Cryptomator
# Create new vault in your cloud sync folder (e.g., ~/Dropbox/Photos-Vault)
# Set a strong password (20+ characters, random)
# Mount the vault → drag photos in
# Dropbox/cloud syncs the encrypted files
# On mobile: Cryptomator iOS/Android app unlocks vault
# Thumbnails are NOT generated server-side (provider sees only ciphertext)
Cryptomator encrypts both file contents and file names — Dropbox sees files with names like 6IQFHU4APB3MSNB.c9r rather than vacation-2025.jpg. This prevents the cloud provider from inferring anything about your library structure.
The main limitation is browsing: you can only view photos while the vault is mounted on a device with Cryptomator installed. There is no web interface for browsing your encrypted photos remotely, and no server-side search or organization tools.
Strip EXIF Metadata Before Sharing
Photos contain metadata that reveals: GPS location, camera model, date/time, sometimes even software used. Before sharing photos publicly or with services that might retain metadata, strip it.
# Install ExifTool
sudo apt install libimage-exiftool-perl # Debian/Ubuntu
brew install exiftool # macOS
# Strip all metadata from a photo
exiftool -all= photo.jpg
# Strip GPS only (keep date/camera info)
exiftool -gps:all= photo.jpg
# Batch process an entire directory
exiftool -all= ~/photos/to-share/
# Verify metadata was removed
exiftool photo.jpg | grep GPS
# Should show nothing
# Keep originals as backup (exiftool renames originals to .jpg_original by default)
# To skip backup creation:
exiftool -all= -overwrite_original photo.jpg
MAT2 (Metadata Anonymization Toolkit) is an alternative that handles a broader range of file formats including PDF, LibreOffice documents, and audio:
sudo apt install mat2
mat2 photo.jpg
mat2 --inplace photo.jpg # overwrite original
Backup Strategy for Self-Hosted Photos
Self-hosted photos require a separate backup strategy — the server itself can fail.
# 3-2-1 backup rule: 3 copies, 2 different media, 1 offsite
# Immich: backup the originals directory and database
# Database backup (run as cron job):
docker exec immich_postgres pg_dump -U postgres immich > ~/backup/immich-db-$(date +%Y%m%d).sql
# Photo files backup to external drive:
rsync -av --delete ~/immich/library/ /media/external-backup/immich/
# Offsite encrypted backup to Backblaze B2 using rclone with crypt remote:
# Configure rclone with a crypt remote pointing at your B2 bucket
rclone sync ~/immich/library/ b2crypt:photos-backup/
# Verify rclone backup integrity:
rclone check ~/immich/library/ b2crypt:photos-backup/
Configure rclone’s crypt remote with Backblaze B2 for zero-knowledge offsite backup:
rclone config
# name: b2crypt
# type: crypt
# remote: b2:your-photos-bucket/encrypted
# filename_encryption: standard
# directory_name_encryption: true
# password: (generate a strong random password)
This gives you encrypted off-site copies that Backblaze cannot read, even though your local Immich installation stores photos unencrypted for performance.
Comparison Summary
| Solution | Privacy | Features | Cost | Complexity |
|---|---|---|---|---|
| Immich (self-hosted) | High | Full | Server cost | Medium |
| PhotoPrism (self-hosted) | High | Good | Server cost | Medium |
| Ente Photos | High (ZK) | Limited | $2+/month | Low |
| Cryptomator + cloud | High | None (browsing only) | Cloud cost | Low-Medium |
| Google Photos | Low | Best | Free/paid | None |
| iCloud + ADP | Medium | Good | $1+/month | Low |
For most users starting from scratch: Ente Photos is the quickest path to meaningful privacy improvement — install the app, pay $2/month, and your photos are encrypted before they leave your device. For developers with a home server: Immich combined with rclone/Backblaze B2 offsite backup delivers Google Photos parity with full control.
Related Reading
- Photographer Client Photo Privacy Protection Cloud Storage
- Best Encrypted Cloud Storage 2026
- How to Audit Your Cloud Storage Privacy
Built by theluckystrike — More at zovo.one