Skip to content
Josh Forrest
Go back

Self-hosting Immich: replacing iCloud Photos

Table of contents

Open Table of contents

Why I bothered

For years my photos lived in iCloud. It was convenient - phone takes a picture, photo appears on every Apple device I own, no thought required. Then I started bumping up against the free 5GB tier, started paying for more, and started thinking about how much of my life - every photo I’d ever taken on a phone - was sitting on Apple’s servers, behind an account I’d lose access to the moment I left the ecosystem, governed by terms of service I’d never read.

Immich is an open-source, self-hosted alternative that has matured rapidly over the last couple of years. It does the things I actually used iCloud Photos for - automatic phone backup, a clean gallery, search, albums, sharing - and it does them on hardware I own, on a network I control, with no monthly fee.

This post is a write-up of how I run it, what I learned getting there, and the bits that took longer than I expected.

Where it runs

Immich runs in an LXC container on proxmox1 in my two-node Proxmox cluster. It sits on the container VLAN (10.10.20.0/24), separated from the Proxmox host network for the same blast-radius reasons I segment everything else.

Storage-wise, Immich’s library lives on the 1TB HDD I have mounted at /mnt/media on proxmox1, exposed into the container as a bind mount at /mnt/media/immich. Originals, uploads, and database backups all live there. The LXC’s own NVMe-backed root disk handles the things that benefit from being fast - thumbnails, the PostgreSQL database - which keeps the gallery responsive even when the underlying media disk is spinning rust.

How it’s exposed

This was the part that took the most thinking. I wanted to be able to upload from my phone wherever I was - out for the day, on holiday, whatever - without opening ports on my home router and without my photos being directly reachable from the public internet.

The answer uses my IONOS edge VPS as an intermediary. The architecture works like this:

  1. A WireGuard tunnel connects the edge VPS to my homelab. The homelab end runs in a dedicated LXC container (CT 113). Critically, both ends of the tunnel are locked down by IP: the VPS can only route to Immich’s specific IP and port (10.10.20.21:2283) through the tunnel, and the homelab-side iptables rules drop everything else.
  2. Nginx on the VPS acts as a reverse proxy - photos.jtforrest.com resolves to the VPS’s public IP, Nginx terminates TLS (via Let’s Encrypt) and forwards the request through the WireGuard tunnel to Immich.
  3. My home IP is never in the picture. The VPS is the only thing publicly reachable, and its blast radius is limited to itself.

This is different from a Cloudflare Tunnel, which I use for some other services. The reason for the distinction is practical: Cloudflare’s free plan has a 100MB upload limit, which makes it unsuitable for photo uploads. The edge VPS approach has no such constraint.

For uploads, the Immich mobile app just points at https://photos.jtforrest.com and runs in the background on my phone the way the iCloud Photos sync used to. New photos get backed up automatically over Wi-Fi or mobile data. I haven’t touched it in months - it just works.

What I gained

A few things have surprised me about running my own photo backup:

What I’d do differently

What’s next

If you’re thinking about getting your photos out of iCloud, Immich is the answer in 2026. Spin it up, request your Apple export, point your phone at it, and you’ll wonder why you didn’t do it sooner.


Share this post on:

Previous Post
Self-hosting AdGuard Home: network-wide ad blocking with no single point of failure
Next Post
Building a two-node Proxmox homelab