Immich - альтернатива Google Photos
Фото на телефоне заканчиваются одинаково: память кончается, облако просит подписку, а «просто посмотреть семейный архив» превращается в передачу личных данных третьей стороне. Immich — self-hosted система хранения и каталогизации фото и видео. Ваше оборудование, ваш сервер, ваши правила. По ощущению — та же облачная галерея, только поиск по лицам и сценам считается дома, а не на чужой машине.
Ветка на момент написания — 3.x. Ставил 3.2.4 поверх 3.1.
Как это устроено
Immich — не один контейнер, а четыре. Лучше знать это до первой поломки:
- immich-server — веб-интерфейс, API, вся логика;
- immich-machine-learning — нейросети: распознавание лиц, семантический поиск, текст на снимках;
- database — PostgreSQL с расширением под векторный поиск;
- redis — очередь задач. Миниатюры, транскодинг видео и скан библиотек уходят в очередь и не считаются в момент вашего запроса.
Порт по умолчанию — 2283. Состояние живёт в двух местах: каталог хранилища (library, upload, thumbs, encoded-video, backups, profile) и каталог данных базы. Удалить одно без другого — получить базу без файлов или файлы без базы.
Установка
Каталог проекта и два файла. Все пути в примерах условные — подставьте свои.
.env:
UPLOAD_LOCATION=/srv/immich/storage
DB_DATA_LOCATION=/srv/immich/db
DB_HOSTNAME=database
DB_PORT=5432
DB_USERNAME=immich
DB_DATABASE_NAME=immich
DB_PASSWORD=***
REDIS_HOSTNAME=redis
REDIS_PORT=6379
TZ=Europe/Moscow
Внимание: этот файл хранит пароль базы открытым текстом. Доступ к каталогу проекта ограничьте, в систему контроля версий он попадать не должен.
docker-compose.yml — сокращённо, показаны сервер и машинное обучение с монтированиями (полный шаблон берётся из официальной документации):
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
ports:
- "2283:2283"
volumes:
- ${UPLOAD_LOCATION}:/data
- /srv/photos/existing-archive:/mnt/archive:ro
env_file: .env
depends_on:
database:
condition: service_healthy
redis:
condition: service_healthy
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /srv/photos/existing-archive:/mnt/archive:ro
env_file: .env
redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0
environment:
POSTGRES_PASSWORD: ***
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
env_file: .env
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 30
restart: always
Обратите внимание на :ro во втором монтировании — об этом ниже.
Запуск:
docker compose pull
docker compose up -d
Первый заход на http://<адрес-сервера>:2283 — мастер попросит создать аккаунт администратора.

Дальше в настройках: включить машинное обучение, при необходимости вход через OAuth (OIDC), SMTP для уведомлений, квоты пользователям.
Перенос уже существующего архива
Главный вопрос при переезде: фото уже лежат папками, десятки и сотни гигабайт. «Загрузить через веб» — плохой путь: Immich копирует всё в своё хранилище, и размер удваивается.
Правильный механизм — внешняя библиотека (external library). Указываете серверу на готовый каталог, он сканирует его и строит хронологию, не дублируя файлы. Монтировать такой каталог советую только на чтение (:ro): тогда сервер физически не сможет удалить или испортить ваш исходный архив.
Грабли, на которые сам успел наступить:
1. Скан не мгновенный. Внешние библиотеки опрашиваются по расписанию — по умолчанию раз в сутки ночью. Положили файлы — и до ночи тишина. Ждать незачем: задачу полного скана можно поставить в очередь вручную, сервер подхватит за минуты. Имя задачи — LibraryScanQueueAll, очередь library, лежит в Redis (BullMQ) под префиксом immich_bull. Проще всего выполнить это из контейнера сервера: там уже есть нужная библиотека и параметры подключения в переменных окружения.
2. Права. Файлы, которые вы кладёте в библиотеку, должен читать пользователь процесса внутри контейнера. Если с хоста файл принадлежит вам и закрыт 600/700, сервер пройдёт мимо молча — без ошибки в логах. Проверяется изнутри контейнера одной командой: ls и head -c 3 на любой jpg — должно быть ff d8 ff. Не читается — чините владельца и права, а не Immich.
3. Как понять, что файл принят. Не смотрите только на число записей в базе. Смотрите, что у объекта есть распарсенный EXIF и что в каталоге миниатюр появились реальные файлы. EXIF пустой — значит сервер содержимое не прочитал (права, битый файл, недоступный путь), а не «всё в порядке, просто нет превью».
Что умеет
- Хронология по дате съёмки, а не по дате загрузки. Избранное, архив, корзина с отложенным удалением.
- Люди — распознавание лиц и группировка в персон. Ошибки правятся вручную: подтвердить, разделить, «не этот человек». Первый прогон на большом архиве считается долго, дальше не пересчитывается каждый раз.
- Умный поиск — семантический, по описанию сцены: «кошка на подоконнике», «ночной город», «документ на столе». Отдельно полнотекстовый поиск по распознанному тексту: находятся скриншоты, документы, чеки.

- Карта — по координатам из EXIF. Геокодирование названий работает офлайн-базой, наружу не стучится.
- Альбомы с совместным доступом, ссылки на просмотр без аккаунта — с сроком жизни и паролем, воспоминания «три года назад».
- Теги — иерархия через слэш (
Работа/Проекты), поиск и фильтрация по ним.

- Несколько пользователей и квоты. У каждого своя хронология. Режим «партнёр» открывает другому человеку просмотр вашей ленты — не весь аккаунт, а именно просмотр. Ровно тот сценарий, ради которого делают семейный архив: два аккаунта, две отдельные библиотеки, ничего общего насильно.
- Дубликаты по хэшу содержимого; stack для серий и пар raw+jpg; видео — транскодинг по требованию и стриминг; конвертация RAW в JPEG на сервере.
- API, ключи API, CLI — автоматизация загрузки и выгрузки.
Полезная мелочь: в базе Immich хранит собственный контрольный хэш файла, и это не md5 и не sha1 содержимого. Сверять копию с оригиналом надо через md5sum по файлам, а не сравнением с полем checksum.
Мобильные приложения
Официальные клиенты — Android и iOS. Подключаются адресом сервера: значит наружу нужен доступ (публичный адрес, туннель или VPN), и HTTPS желателен — иначе приложение гоняет фото открытым текстом.

Главная функция — фоновое резервное копирование. Настраивается: какие папки, по какой сети (Wi-Fi или мобильные данные), только на зарядке или всегда, включать ли видео.

Есть опция «удалить с устройства после загрузки» — включайте её, только когда точно уверены в бэкапе: приложение честно удалит исходники с телефона.
Приятное: дубли не грузятся дважды, а на втором телефоне достаточно указать тот же сервер и аккаунт — вся хронология уже на месте. Совместный доступ в приложении выглядит так же, как в вебе.

После обновления сервера проверяйте клиент: если приложение ругается на версию, обновляйте сервер и телефон синхронно.
Эксплуатация
Обновление. Проверено на переходе 3.1 → 3.2: миграции базы отработали на старте контейнера, руками чинить не пришлось. Порядок, который считаю правильным:
- Прочитать release notes — искать Breaking Changes и требование к минимальной версии клиента.
- Сделать дамп базы и обязательно проверить, что он читается, а не просто весит больше нуля:
docker exec -t immich_postgres pg_dump -U immich -d immich --format=custom -f /tmp/immich.dump
pg_restore --list /tmp/immich.dump | tail -5
- Обновить образы и пересоздать контейнеры:
docker compose pull && docker compose up -d. - Проверить: контейнеры
healthy, веб отвечает, число объектов в базе совпадает с ожиданием, ошибок вdocker logsнет.
Даже если база страхуется регулярным бэкапом, дамп перед миграцией делаю всегда: миграция необратима, а дамп стоит секунды.

Резервные копии. Нужны оба куска: файлы хранилища и данные базы. Только файлы — потеряете хронологию, лица, альбомы. Только база — потеряете сами фотографии.
Свободное место. Если файловая система с копированием при записи и снимками (btrfs, ZFS), удаление не вернёт место мгновенно: снимки держат блоки до своей ротации. Картина «удалил 20 ГБ, а df не изменился» — чаще всего именно это, а не «место не освободилось».
Итог
Self-hosted фотоархив с лицами, умным поиском, картой, семейными аккаунтами и мобильным автосканом — без подписки и без чужого сервера, где лежат ваши фотографии. Цена: четыре контейнера, обновления синхронно с мобильным клиентом и одна привычка — дамп базы перед каждым апдейтом.
Иллюстрации — скриншоты интерфейса из официальной документации Immich (docs.immich.app). На одном скриншоте адрес сервера закрыт заглушкой.