За последние годы хранение фотографий стало отдельной задачей. Телефоны снимают всё больше, видео легко уходит в 4K, а домашний архив незаметно разрастается до сотен гигабайт. При этом облачные сервисы становятся дороже, ограничения меняются, а зависимость от одного аккаунта или провайдера не всем подходит.
Если дома уже есть сервер, NAS или небольшой homelab, логичный вариант — забрать фотоархив под свой контроль. Для этого хорошо подходит Immich — open source сервис для хранения фотографий и видео, который по логике работы очень похож на Google Photos, но разворачивается на своей инфраструктуре.
Что такое Immich
Immich — это self-hosted платформа для хранения, просмотра и синхронизации фотографий и видео.
Идея простая: поднимаем сервис на своём сервере, ставим приложение на телефон, включаем автозагрузку — и новые фото автоматически попадают в личное хранилище.
При этом Immich — это не просто папка с файлами. У него есть веб-интерфейс, мобильное приложение, альбомы, поиск, карта, распознавание лиц, поддержка нескольких пользователей и импорт внешних библиотек.
Для домашнего фотоархива этого более чем достаточно.
Зачем нужен Immich
Основная причина — контроль над своими данными.
Типичные сценарии:
- надоело платить за Google One, iCloud или Яндекс 360;
- хочется хранить оригиналы фото и видео у себя;
- нужен нормальный семейный фотоархив;
- уже есть домашний сервер или NAS;
- хочется самому контролировать резервные копии;
- нет желания зависеть от одного облачного аккаунта.
Главное преимущество Immich в том, что данные лежат у вас: на вашем сервере, диске, NAS или RAID-массиве. Не у стороннего провайдера и не в чужой инфраструктуре.
Основные возможности
Immich закрывает большую часть задач, которые обычно нужны для личного или семейного фотоархива.
Автозагрузка с телефона
Мобильное приложение умеет автоматически загружать фотографии и видео на сервер. Это один из главных сценариев использования Immich.
Можно настроить:
- какие альбомы синхронизировать;
- загружать ли видео;
- использовать только Wi-Fi или ещё и мобильную сеть;
- выполнять ли загрузку в фоне.
По сути, это замена автозагрузке Google Photos, iCloud или Яндекс.Диска.
Веб-интерфейс
Через браузер можно смотреть фотографии, создавать альбомы, скачивать файлы, управлять пользователями и просматривать архив по датам.
Интерфейс у Immich достаточно современный. Это не файловый менеджер в стиле «папка за папкой», а именно медиатека с временной шкалой.
Распознавание лиц
Immich умеет группировать фотографии по лицам. Для семейного архива это полезная функция: можно быстро найти фотографии конкретного человека за разные годы.
Обработка выполняется локально на сервере. Ничего не нужно отправлять во внешние облака.
Поиск, карта и метаданные
Immich читает EXIF-данные: дату съёмки, координаты, модель устройства и другую техническую информацию.
Если у фотографии есть геометка, её можно посмотреть на карте. Для поездок и старых архивов это удобно: иногда проще вспомнить место, чем дату.
Альбомы и пользователи
В Immich можно создавать альбомы, делиться ими с другими пользователями и заводить отдельные аккаунты для семьи.
Это делает сервис удобным не только для одного пользователя, но и для домашнего использования несколькими людьми.
Почему не просто папка с фото
Можно сказать: «А зачем Immich, если есть Syncthing, Nextcloud или обычная шара по SMB?»
Ответ простой: обычная папка решает только задачу хранения. Immich решает задачу фотоархива.
Он умеет:
- показывать фотографии по временной шкале;
- делать превью;
- искать по архиву;
- показывать фотографии на карте;
- группировать людей;
- работать с мобильным приложением;
- удобно открывать архив с телефона и браузера.
То есть Immich — это не просто файловое хранилище. Это полноценная медиатека.
Вариант установки через Docker Compose
Для домашнего сервера самый удобный способ установки — Docker Compose.
Типовая схема состоит из нескольких компонентов:
-
immich-server— основной backend; -
immich-machine-learning— обработка ML-функций; -
postgres— база данных; -
redis— очередь и кэш; - директория с фотографиями и видео.
Пример структуры проекта:
/opt/immich/
├── docker-compose.yml
└── .env
/mnt/storage/immich/
├── upload/
├── postgres/
└── ml-cache/
Фотографии лучше хранить не на системном диске, а на отдельном HDD, SSD, RAID-массиве или NAS. Фотоархив быстро растёт, особенно если с телефона загружаются видео.
Установка Immich через Docker Compose
Создадим отдельную директорию под проект:
mkdir -p /opt/immich
cd /opt/immich
Создаём файл docker-compose.yml:
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- ${IMMICH_MACHINE_LEARNING_CACHE}:/cache
env_file:
- .env
restart: always
redis:
container_name: immich_redis
image: redis:6.2-alpine
restart: always
database:
container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg16-v0.3.0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: postgres
POSTGRES_DB: immich
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
restart: always
volumes: {}
Теперь создаём файл .env рядом с docker-compose.yml:
nano .env
Пример содержимого:
IMMICH_VERSION=release
UPLOAD_LOCATION=/mnt/storage/immich/upload
DB_DATA_LOCATION=/mnt/storage/immich/postgres
IMMICH_MACHINE_LEARNING_CACHE=/mnt/storage/immich/ml-cache
DB_PASSWORD=
Что здесь важно:
-
UPLOAD_LOCATION— директория, куда Immich будет сохранять фотографии и видео; -
DB_DATA_LOCATION— директория с данными PostgreSQL; -
IMMICH_MACHINE_LEARNING_CACHE— кэш для модуля машинного обучения; -
DB_PASSWORD— пароль от базы данных.
Перед запуском создадим нужные директории:
mkdir -p /mnt/storage/immich/upload
mkdir -p /mnt/storage/immich/postgres
mkdir -p /mnt/storage/immich/ml-cache
Запускаем Immich:
docker compose up -d
Проверяем контейнеры:
docker compose ps
После запуска веб-интерфейс будет доступен по адресу:
http://IP_ВАШЕГО_СЕРВЕРА:2283
Например:
http://192.168.1.10:2283
При первом входе Immich предложит создать администратора. После этого можно ставить мобильное приложение Immich на телефон и включать автоматическую загрузку фото и видео.
Обновление Immich
Обновление выполняется стандартно:
cd /opt/immich
docker compose pull
docker compose up -d
Перед обновлением лучше сделать резервную копию базы и директории с фотографиями. Особенно если обновление крупное.
Резервное копирование
Immich не заменяет бэкапы. Это важный момент.
Минимально нужно резервировать:
/opt/immich/docker-compose.yml
/opt/immich/.env
/mnt/storage/immich/upload
/mnt/storage/immich/postgres
Особенно важны две директории:
/mnt/storage/immich/upload
/mnt/storage/immich/postgres
Первая содержит оригиналы фотографий и видео.
Вторая содержит базу данных Immich.
Если потерять контейнеры — их можно пересоздать.
Если потерять базу или оригиналы — восстановление будет намного сложнее.
Для нормальной схемы я бы делал минимум так:
- локальный бэкап базы PostgreSQL;
-
отдельный бэкап директории
upload; - периодическую копию на другой диск, NAS или внешний сервер;
- проверку восстановления хотя бы разово.
Фотоархив обычно ценнее большинства сервисов в homelab, поэтому относиться к нему надо аккуратно.
Миграция фото и видео в Immich через API
После установки Immich можно залить в него уже существующий архив. У меня это была локальная папка с фотографиями и видео, выгруженными из Яндекс.Диска.
Для загрузки использовал простой Python-скрипт. Он проходит по папке, находит медиафайлы и отправляет их в Immich через API.
Сначала ставим зависимость:
pip install requests
Создаём файл:
nano immich_migrate.py
Сам скрипт:
#!/usr/bin/env python3
"""Migrate local photos/videos to Immich via API."""
from __future__ import annotations
import argparse
import datetime as dt
import sys
from pathlib import Path
from typing import Iterable
import requests
DEFAULT_SOURCE_DIR = Path(r"E:\YandexDisk Photo\Фото и видео из Яндекс.Диска")
DEFAULT_IMMICH_URL = ""
DEFAULT_IMMICH_API_KEY = ""
DEVICE_ID = "local-yadisk-migration-script"
MEDIA_EXTENSIONS = {
".jpg", ".jpeg", ".png", ".webp", ".heic", ".heif", ".gif", ".bmp", ".tif", ".tiff",
".mp4", ".mov", ".avi", ".mkv", ".webm", ".3gp", ".mts", ".m2ts",
}
def info(msg: str) -> None:
print(f"[INFO] {msg}")
def warn(msg: str) -> None:
print(f"[WARN] {msg}")
def err(msg: str) -> None:
print(f"[ERR ] {msg}")
def is_media_file(path: Path) -> bool:
return path.is_file() and path.suffix.lower() in MEDIA_EXTENSIONS
def collect_media_files(source_dir: Path) -> list[Path]:
return sorted(p for p in source_dir.rglob("*") if is_media_file(p))
def to_utc_iso(timestamp: float) -> str:
dt_obj = dt.datetime.fromtimestamp(timestamp, tz=dt.timezone.utc)
return dt_obj.isoformat()
def build_device_asset_id(source_root: Path, file_path: Path) -> str:
rel = file_path.relative_to(source_root)
return rel.as_posix()
def upload_to_immich(immich_url: str, api_key: str, source_root: Path, file_path: Path) -> None:
url = immich_url.rstrip("/") + "/api/assets"
headers = {"x-api-key": api_key}
stat = file_path.stat()
modified_at = to_utc_iso(stat.st_mtime)
created_at = to_utc_iso(stat.st_ctime)
data = {
"deviceAssetId": build_device_asset_id(source_root, file_path),
"deviceId": DEVICE_ID,
"fileCreatedAt": created_at,
"fileModifiedAt": modified_at,
"isFavorite": "false",
}
with file_path.open("rb") as file_obj:
files = {"assetData": (file_path.name, file_obj)}
response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
if response.status_code >= 400:
body = response.text[:500].replace("\n", " ")
raise RuntimeError(f"Immich API error {response.status_code}: {body}")
def migrate(source_dir: Path, immich_url: str, api_key: str, dry_run: bool) -> tuple[int, int]:
files = collect_media_files(source_dir)
info(f"Найдено медиафайлов: {len(files)}")
success = 0
failed = 0
for i, file_path in enumerate(files, start=1):
rel = file_path.relative_to(source_dir)
info(f"[{i}/{len(files)}] {rel}")
if dry_run:
print(f"[DRY ] Загрузил бы: {file_path}")
success += 1
continue
try:
upload_to_immich(immich_url=immich_url, api_key=api_key, source_root=source_dir, file_path=file_path)
success += 1
except Exception as ex:
failed += 1
err(f"Ошибка загрузки '{file_path}': {ex}")
return success, failed
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Migrate local media files to Immich")
parser.add_argument("--source", default=str(DEFAULT_SOURCE_DIR), help="Source folder with photos/videos")
parser.add_argument("--immich-url", default=DEFAULT_IMMICH_URL, help="Immich base URL")
parser.add_argument("--immich-api-key", default=DEFAULT_IMMICH_API_KEY, help="Immich API key")
parser.add_argument("--dry-run", action="store_true", help="Show what would be uploaded")
return parser.parse_args()
def main() -> int:
args = parse_args()
source_dir = Path(args.source).resolve()
if not source_dir.exists() or not source_dir.is_dir():
err(f"Папка не найдена: {source_dir}")
return 1
info(f"Источник: {source_dir}")
info(f"Immich: {args.immich_url}")
if not args.immich_api_key:
err("Не указан Immich API key")
return 1
try:
success, failed = migrate(
source_dir=source_dir,
immich_url=args.immich_url,
api_key=args.immich_api_key,
dry_run=args.dry_run,
)
except Exception as ex:
err(f"Критическая ошибка: {ex}")
return 1
info(f"Готово. Успешно: {success}, Ошибок: {failed}")
return 0 if failed == 0 else 2
if __name__ == "__main__":
sys.exit(main())
Внутри скрипта нужно указать адрес Immich и API-ключ:
DEFAULT_IMMICH_URL = "https://cloud.example.ru"
DEFAULT_IMMICH_API_KEY = "ваш_api_ключ"
Что важно учесть перед установкой
Перед развёртыванием Immich стоит сразу продумать несколько моментов.
Диски
Фото и видео занимают много места. Если сейчас архив весит 500 ГБ, через пару лет он спокойно может вырасти до 1–2 ТБ.
Не стоит размещать библиотеку на системном диске. Лучше сразу вынести данные на отдельный накопитель или массив.
Ресурсы сервера
Для простого хранения Immich не требует мощного сервера. Но генерация превью, индексация, распознавание лиц и ML-функции могут заметно нагружать CPU.
При первом запуске на большом архиве сервер может какое-то время активно работать. Это нормально.
Доступ из интернета
Если нужен доступ извне, я бы не открывал Immich напрямую в интернет без дополнительной защиты.
Нормальные варианты:
- VPN;
- reverse proxy с HTTPS;
- Cloudflare Tunnel;
- Authelia или Authentik;
- ограничение доступа по IP;
- отдельный домен.
Для домашнего фотоархива простой проброс порта наружу — не лучший вариант.
Для кого подходит Immich
Immich хорошо подойдёт тем, кто:
- держит домашний сервер или NAS;
- хочет уйти с Google Photos, iCloud или Яндекс.Диска;
- хранит большой семейный фотоархив;
- хочет автозагрузку фотографий с телефона;
- хочет контролировать свои данные;
- готов сам обслуживать сервис и бэкапы.
Если не хочется заниматься сервером, обновлениями и резервным копированием, коммерческое облако будет проще. Но контроля над данными там будет меньше.
Итог
Immich — один из лучших self-hosted вариантов для личного фотоархива. Он закрывает основные сценарии, которые раньше обычно решались через Google Photos, iCloud или Яндекс.Диск: автозагрузка с телефона, удобный просмотр, альбомы, поиск, карта и распознавание лиц.
Для homelab это почти обязательный сервис, если хочется хранить фотографии у себя, а не зависеть от внешних облаков.
Главное — не забывать про бэкапы. Immich удобно хранит и показывает фотографии, но ответственность за сохранность архива всё равно остаётся на владельце сервера.
Интересно