# Building a Self-Hosted Photo Library That Survives Real Life

## Why I Moved Photos Home

Cloud photo services are convenient until you care about originals, export formats, recurring costs, or what happens when an account gets locked. I wanted a library that kept full-resolution files on hardware I control, still offered phone uploads and fast browsing, and did not require treating my photo archive like a side project every weekend.

## Storage Layout

The most important decision was keeping the photo library separate from the application database. The app can generate thumbnails, embeddings, and metadata indexes, but the original files need a boring, predictable layout on disk. I use one dataset for originals, one for app state, and one read-only backup target so a bad container update cannot accidentally rewrite years of images.

## Running the Service

I run the library with Docker Compose, backed by a local PostgreSQL database and a mounted media directory. The exact application matters less than the boundaries: persistent volumes, explicit paths, pinned versions, and no “latest” tags in production.

```yaml
services:
  photos:
    image: ghcr.io/immich-app/immich-server:v1.108.0
    volumes:
      - /srv/photos/originals:/usr/src/app/upload
    env_file:
      - .env
    depends_on:
      - database
```

## Ingestion and Backups

Phone uploads go into an import queue first, then the library processes thumbnails and metadata in the background. Backups run independently of the photo app: nightly snapshots stay on the NAS, weekly copies go to external storage, and a monthly restore test confirms that both the files and database can be rebuilt together.

## Lessons Learned

The library feels reliable because it is intentionally uninteresting. The UI can change, the containers can be replaced, and the indexing engine can improve, but the originals remain plain files with multiple backups. For a photo archive, that separation is more valuable than any single feature.