In my homelab post I said I tried Ente first, couldn’t get it working, and went with Immich. I also said I’d try Ente again someday. Took a while, but I did.
Why
Immich was fine. Honestly it was more than fine. But it’s not end-to-end encrypted, so anything on the server can be read by whoever gets into the server. If something ever leaked, my photos go with it. I also wanted to give a friend some space on the box, and I didn’t like the idea of their photos sitting there in the open either.
With Ente the photos get encrypted on the phone before they’re uploaded. My server just stores stuff it can’t read.
Round One
End of last year I spent around three days on this and gave up.
Ente stores files in S3-style storage (MinIO), and the apps upload directly to it using links the server gives them. Those links kept pointing to addresses my phone couldn’t reach. When I fixed that, the browser started blocking them because they were plain HTTP behind Cloudflare. Fix one thing, something else breaks. Meanwhile Immich took an hour to set up. Easy choice at the time.
Round Two
This time I didn’t try to do everything at once. In October I set up just Ente Locker, their file storage app, to see if I could get the server itself working properly. It did. A few days later I added Photos and moved everything over in one night.
The thing I didn’t get the first time is pretty simple once you see it. The storage address has to work from everywhere. The server, my phone, my laptop, all of them need to reach it using the same name. I gave it a proper hostname and the upload problems just stopped.
Some other dumb stuff I hit along the way. .dev domains force HTTPS in browsers, so my plain-HTTP internal names didn’t load at all, which took me longer to figure out than I’d like to admit. Cloudflare’s free certificate only covers one level of subdomain, so a name like albums.lab.mydomain can’t be public. And a self-hosted account starts with a 10 GB limit, which you have to raise yourself with the CLI after making yourself an admin.
The Setup
Same mini PC, same Traefik, photos on the same RAID. I’m using Silo for storage, which is a fork of MinIO.
It’s also lighter than Immich. Around 600 MB of RAM for all of Ente versus roughly 1.8 GB for Immich. Makes sense, since the server isn’t doing the heavy lifting anymore.
Everything is behind Headscale. My phone and laptop talk to the homelab over the tailnet, even for the “public” names, because Headscale’s DNS points those straight at the mini PC. Cloudflare never sees my own traffic.
Sharing Without Opening Everything Up
The one thing that needs to be public is share links. If I send someone an album, they’re not going to install Tailscale for it.
My first version of this was lazy. I put the album page, the whole Ente API and the storage behind Cloudflare Tunnel and called it done. Sign-ups were off and 2FA was on, so I figured that was fine. Within a few days the logs were full of bots trying /.env, /.git/HEAD, /debug/pprof and so on. None of it worked, but every one of those requests was reaching Ente. The login endpoints were right there on the internet for anyone to hammer, all for a feature that only needs a tiny slice of the API.
So I locked it down. To figure out what a share link actually needs, I went through the albums web app’s JavaScript and noted every API call it makes. Turns out it’s all under two paths, one for shared albums and one for shared memories. Traefik now only lets those two through on the public side. Everything else, login included, gets a plain 404 from Traefik and never reaches Ente at all.
Storage got the same treatment. The server hands out signed links for every photo, so the public side only accepts requests that carry a signature, plus the browser’s CORS check. No signature, no access. You can’t even list what’s in there, and deletes are blocked no matter what.
Then I tested it from outside the tailnet. Albums open, photos load, and even uploading into a shared album with “Allow adding photos” works. Login from the public URL is just a 404 now. Over Headscale everything still works like before.
What I haven’t done yet is any rate limiting, or anything on the Cloudflare side. That’s probably next.
Moving the Photos
About 6,400 files, 68 GB, going back to 2022. Mostly photos, a few hundred videos.
There’s no Immich to Ente importer. But the Ente desktop app can import Google Takeout exports, which are just photos with a little JSON file next to each one holding the date, location and so on. So I wrote a Python script that exports everything from Immich in that same format. Dates, locations, descriptions and favourites all made it across.
I tried 30 of the weirdest files I could find first. Videos, HEIC, screenshots with no camera info, long file names, live photos. All good. Then I let the full thing run from the desktop app on my laptop. Started around 4:30 in the morning and it was done before 8. Two files failed, and both were the CSV file my own script made, so that doesn’t count.
Face recognition in Ente happens on your own device, so my laptop chewed through the whole library on CPU. It found about 13,000 faces. Face names didn’t carry over from Immich, so I’m slowly redoing those.
Backups
Every night the database and configs get dumped to the RAID, and the photos get copied to AWS S3 Glacier Deep Archive. Since Ente already encrypted everything, AWS can’t see my photos either. It costs me something like $0.15 a month.
I’ll be honest, I haven’t tried a full restore yet. Getting stuff back out of Deep Archive takes hours and costs money, so I keep putting it off. I know, I know.
So, Is It Better?
The app feels nicer than Immich’s. And the memories feature is great. It keeps showing me old photos I’d completely forgotten I had. Browsing can be a bit slower though. I think it’s because Ente has to download the full photo and decrypt it on the phone, and my photos live on an old 5400 rpm laptop drive. Haven’t really checked yet.
There are two things I miss. First, Immich doing all the smart stuff on the server. Face groups and search just worked without my phone or laptop doing anything. With Ente the indexing has to happen on one of my devices. It only needs to happen once, since the results get encrypted and synced to the others, but my laptop still had to chew through the whole library to get there. That’s the price of the server not being able to see anything, and I’m okay paying it.
The other one is Immich’s network switching. I had it set up to use the local address when I’m on home Wi-Fi, Headscale when I’m out, and the public URL as a last resort. Ente just takes one server address, so now everything goes through Headscale, even when the phone is sitting right next to the mini PC.
If you just want Google Photos at home, go with Immich. It’s easier. If it bugs you that your server can read your photos, Ente is worth the extra effort. Just don’t try to do it all in one weekend like I did the first time.