Ente Photos is the rare open-source album with end-to-end encryption: photos are encrypted on the device before upload and the server only holds ciphertext. It ships iOS, Android, web and desktop clients, so a self-hosted instance can fully replace a cloud album. This guide follows the official quickstart and covers the parts that actually matter — domains, HTTPS and backups.
1. Three things to know first
- The mobile app requires HTTPS. Your self-hosted server address must start with
https://; a bare IP over HTTP will not connect. Prepare two domains, for examplephotos.example.com(web) andapi.example.com(API). - At least 2 vCPU / 4 GB, photos in object storage (MinIO or external S3), PostgreSQL for the database.
museum.yamlis a key file. It holds database and object-storage credentials; lose it and the data is effectively unreadable. Back it up.
2. Images and ports
| Service | Image | Port |
|---|---|---|
| museum (API) | ghcr.io/ente-io/server | 8080 |
| web (Photos) | ghcr.io/ente/web | 3000 |
| web (public albums) | ghcr.io/ente/web | 3002 |
| postgres | postgres:15 | internal |
| minio | pgsty/silo | 3200 |
3. Generate the config with the official quickstart
mkdir -p /opt/ente && cd /opt/ente
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ente/ente/main/server/quickstart.sh)"
The script creates my-ente/ containing compose.yaml and museum.yaml with random passwords already filled in:
cd my-ente
ls -l
docker compose up -d
docker compose ps
Once running, locally you get Photos at http://IP:3000, the API at http://IP:8080/ping and public albums at http://IP:3002.
4. Switch to your own domains and public addresses
By default the S3 endpoint in museum.yaml points at localhost:3200, which only works for local testing. For mobile uploads the client must be able to reach object storage. Two options:
- Simple: give MinIO an HTTPS domain too (for example
s3.example.com), changeendpointinmuseum.yamltos3.example.com, and proxy it to port3200. - Recommended: use external S3 in production (Cloudflare R2, Backblaze B2, Alibaba OSS and so on), set
are_local_bucketstofalseand fill in key, secret and endpoint.
Also change ENTE_API_ORIGIN for the web service in compose.yaml to https://api.example.com, otherwise the frontend keeps calling localhost.
5. Reverse proxy
Proxy the three entry points separately, and watch upload size and timeouts:
server {
listen 443 ssl http2;
server_name photos.example.com;
ssl_certificate /etc/letsencrypt/live/photos.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photos.example.com/privkey.pem;
client_max_body_size 0;
proxy_request_buffering off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 600s;
}
}
Repeat with api.example.com → 8080, albums.example.com → 3002 and s3.example.com → 3200 if you keep local MinIO.
6. Sign-up and verification codes
- Open
https://photos.example.comand register. - Registration needs an email code. A self-hosted instance does not send mail, so the code is printed in the museum logs:
docker compose logs museum | grep -i "verification\|otp" | tail -20
- After signing in, create albums and invite family. In the mobile app go to Settings → Server → Custom server and enter
https://api.example.com.

7. Backups
my-ente/museum.yaml: credentials and keys, back up separately.- PostgreSQL volume:
docker compose exec postgres pg_dump -U pguser ente_db > ente.sql. - MinIO volume (or external S3 bucket): the encrypted photo bodies.
You need all three. Schedule a weekly backup of the database and museum.yaml, and enable versioning on the object storage bucket.

8. Troubleshooting
The app cannot reach the server? 99% of the time it is HTTPS or the certificate. Open https://api.example.com/ping in the phone browser first; it must return pong.
Uploads fail? Check that the S3 endpoint in museum.yaml is a public address the phone can reach, and that the bucket exists.
Forgot the admin password? Ente passwords participate in key derivation and cannot be reset server-side. Keep your recovery key safe.
9. Wrap-up
Ente is a little more work to deploy than Immich, and what you buy is "the server cannot see my photos". If privacy matters and you want a near-commercial experience, it is worth the extra hour.
Related: Immich tutorial · 2026 self-hosted album comparison


