Self-Hosting Ente: End-to-End Encrypted Google Photos Alternative
Google Photos is convenient. It’s also a privacy nightmare — your photos are scanned, analyzed, and stored on servers you don’t control. If you’ve been looking for a self-hosted alternative that doesn’t sacrifice the features that make cloud photo management actually useful, Ente deserves serious consideration.
Ente is a fully open-source, end-to-end encrypted photo storage platform. Every photo is encrypted on your device before it ever touches your server. Not even you (as the server admin) can see the contents of uploaded photos without the user’s encryption keys. It’s been audited by Cure53, one of the most respected cybersecurity firms in the world, along with Symbolic Software for cryptography and Fallible for penetration testing.
But encryption isn’t the only reason to care about Ente. It ships with face detection, semantic search, collaborative albums, family plans, private sharing, background uploads on mobile, and native apps for iOS, Android, Web, Linux, macOS, and Windows. This isn’t a compromise — it’s a genuine replacement.
Why Ente Over Other Self-Hosted Photo Solutions
The self-hosted photo management space has several options, and they all take different approaches.
Immich is the most popular self-hosted Google Photos alternative right now. It’s fast-moving, feature-rich, and has excellent mobile apps. However, Immich doesn’t offer end-to-end encryption. Your photos are stored unencrypted on the server, which means anyone with server access can view them.
PhotoPrism is mature and powerful with AI-powered tagging and a polished web interface. Like Immich, it stores photos unencrypted. It’s also more resource-hungry and lacks native mobile apps.
Nextcloud Photos integrates with the broader Nextcloud ecosystem but is generally considered clunky compared to purpose-built photo apps. Performance can be an issue at scale.
Ente’s differentiator is clear: true end-to-end encryption with a polished user experience. If privacy is non-negotiable for you, Ente is currently the only self-hosted option that encrypts everything client-side while still providing features like face recognition and semantic search (these run on-device, not on your server).
How Ente’s Architecture Works
Understanding Ente’s architecture helps you plan your deployment:
- Museum — The server component, written in Go. It handles authentication, metadata, and coordinates storage. It’s lightweight and runs well on minimal hardware.
- PostgreSQL — Stores user data, album metadata, and server state.
- MinIO (or S3-compatible storage) — Object storage for encrypted photo blobs. The default quickstart uses MinIO, but you can swap in any S3-compatible provider.
- Web apps — Ente Photos, Auth, Albums, Cast, and Accounts are separate web frontends served as static apps.
The key insight: Museum never sees unencrypted photo data. It stores encrypted blobs and serves them back to clients, which decrypt locally. This means your server requirements are mainly about storage capacity and network bandwidth, not compute power.
Prerequisites
Before you begin, make sure you have:
- A Linux server (Ubuntu or Debian recommended) with at least 1 GB of RAM and 1 CPU core
- Docker and Docker Compose v2.30+ installed (note: the legacy
docker-composecommand is not supported — usedocker compose) - Sufficient storage space for your photo library (plan for roughly 1.5x your library size to account for thumbnails and metadata)
- A domain name pointed at your server (required for HTTPS, which Museum mandates for security)
- Basic familiarity with the Linux command line
Step 1: Quick Setup with the Official Script
Ente provides a quickstart script that handles the initial configuration:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ente-io/ente/main/server/quickstart.sh)"
This creates a my-ente directory in your current working directory containing:
compose.yaml— Docker Compose configuration for all servicesmuseum.yaml— Server configuration file- Required data directories
After the script finishes, start the cluster:
cd my-ente
docker compose up -d
Wait for all containers to pull and start. You can check the status with:
docker compose ps
You should see containers for Museum (the server), PostgreSQL, MinIO, and the web apps.
Step 2: Create Your First User
With the cluster running, open the Ente Photos web app at http://localhost:3000 (or replace localhost with your server’s IP if accessing remotely).
Click “Don’t have an account?” and follow the signup prompts. Enter your email and create a password.
Ente will generate a verification code. Since you’re self-hosting, this code appears in the server logs rather than being emailed:
docker compose logs | grep -i "verification"
Enter the code to complete registration. The first user created is automatically the admin.
Step 3: Whitelist Yourself as Admin
To access admin features, explicitly whitelist your user ID:
# Connect to the database
docker exec -it <postgres-container-name> sh
psql -U pguser -d ente_db
Find your user ID:
SELECT user_id, email FROM users;
Note the user_id value, then exit psql (\q) and the container (exit).
Edit museum.yaml to add your admin user:
internal:
admins:
- 1234567890 # Replace with your actual user_id
Restart the cluster to apply changes:
docker compose down && docker compose up -d
Step 4: Configure a Reverse Proxy
Museum requires HTTPS for security — it won’t accept plain HTTP traffic in production. We recommend Caddy for its automatic certificate management.
Install Caddy:
sudo apt install caddy
sudo systemctl enable --now caddy
Edit /etc/caddy/Caddyfile:
Reload Caddy:
sudo systemctl reload caddy
Make sure you’ve created the corresponding A/AAAA DNS records pointing to your server’s IP.
Step 5: Update Museum Configuration
Edit museum.yaml to configure your endpoints so the apps know where to find each other:
apps:
public-albums: https://albums.yourdomain.com
accounts: https://accounts.yourdomain.com
You’ll also want to review the S3/MinIO configuration in museum.yaml. The default setup uses a local MinIO instance, which is fine for getting started. For production, consider:
- External S3-compatible storage (Backblaze B2, Wasabi, AWS S3) for durability and scalability
- Configuring replication if you want redundancy beyond what your single server provides
Restart after configuration changes:
docker compose down && docker compose up -d
Step 6: Connect Mobile Apps
Install Ente Photos from the App Store, Google Play, or F-Droid.
To point the app at your self-hosted instance:
- Open the app
- Tap the “Self-hosting” or server settings option on the login screen
- Enter your Museum API endpoint:
https://api.photos.yourdomain.com - Log in with the account you created earlier
Background uploads will automatically encrypt and sync new photos from your device.
Step 7: Import Your Existing Library
If you’re migrating from Google Photos, download your library via Google Takeout. Select only Google Photos, choose .zip format, and request the export.
Once downloaded, you can upload through the web interface or use the Ente CLI for bulk imports:
# Install the Ente CLI
# Check the latest release at https://github.com/ente-io/ente/releases
# for the CLI binary
# Export from Google Takeout and upload
ente upload --dir /path/to/google-takeout/Google\ Photos
The CLI handles deduplication and preserves metadata, making it the best option for large libraries.
Storage Considerations
Photo libraries grow fast. Here’s how to plan your storage:
- Average photo size: 3-5 MB (smartphones), 20-50 MB (RAW files)
- 1,000 photos ≈ 3-5 GB (compressed), up to 50 GB (RAW)
- Thumbnails and metadata add roughly 10-20% overhead
- Encrypted blobs are slightly larger than originals due to encryption overhead
For a typical smartphone library of 20,000 photos, budget around 80-120 GB of storage.
Using External Object Storage
For larger libraries or better durability, configure an external S3-compatible provider in museum.yaml:
s3:
are_local_buckets: false
b2-eu-cen:
key: your-key-id
secret: your-secret-key
endpoint: s3.eu-central-003.backblazeb2.com
region: eu-central-003
bucket: your-ente-bucket
Backblaze B2 and Wasabi are popular choices among self-hosters for their competitive pricing ($6/TB/month or less).
Troubleshooting
Container won’t start or keeps restarting
Check logs for the specific failing container:
docker compose logs museum
docker compose logs postgres
Common causes: port conflicts (8080, 3000, 3001, 3002), insufficient permissions on data directories, or Docker Compose version too old (needs 2.30+).
Can’t receive verification code
The code is in the server logs, not sent by email (unless you’ve configured SMTP):
docker compose logs | grep -i "OTP\|code\|verification"
CORS errors when uploading photos
This typically happens when accessing Ente via IP address instead of a domain name. The browser blocks cross-origin requests between different ports. Solution: use a domain name with a reverse proxy (as configured in Step 4) or access via Tailscale.
Mobile app can’t connect
Verify that:
- Your Museum endpoint uses HTTPS (not HTTP)
- DNS is resolving correctly
- Firewall allows traffic on ports 80 and 443
- The API endpoint URL doesn’t include a trailing slash
High memory usage
If MinIO is consuming too much RAM, you can limit it in your compose.yaml:
services:
minio:
deploy:
resources:
limits:
memory: 512M
Backup Strategy
Even though Ente encrypts everything, you should still back up:
- PostgreSQL database — Contains user data and metadata. Use
pg_dumpon a schedule:docker exec <postgres-container> pg_dump -U pguser ente_db > ente_backup_$(date +%Y%m%d).sql - MinIO data directory — Contains the encrypted photo blobs. Back up the data volume or configure MinIO replication.
- museum.yaml — Your server configuration. Keep a copy somewhere safe.
Ente Auth: Bonus Two-Factor Authenticator
While you’re at it, Ente also offers Ente Auth — a free, end-to-end encrypted 2FA authenticator that runs on the same infrastructure. It’s accessible at http://localhost:3003 by default and serves as a solid replacement for Authy (which was deprecated).
If you’ve already set up the full stack, Ente Auth works out of the box with the same user accounts.
Conclusion
Ente stands out in the self-hosted photo space by solving a problem nobody else has: giving you a polished, feature-rich Google Photos experience with genuine end-to-end encryption. Your server stores encrypted blobs it can’t read. Face detection and search happen on-device. And the mobile apps handle background uploads seamlessly.
The tradeoff is that server-side AI features (like the smart categorization you’d get with Immich or PhotoPrism) aren’t possible when the server can’t see your photos. But if privacy is your priority — and you’re reading a self-hosting guide, so it probably is — that’s exactly the point.
For most home users, the quickstart setup with local MinIO storage will work perfectly. As your library grows, swap in external S3 storage and you’ve got a photo backup system that scales to hundreds of thousands of photos while keeping everything encrypted and under your control.