MAATRIX / Блог / PhotoPrism в Docker Compose: готовый файл

PhotoPrism в Docker Compose: готовый файл

MAATRIX

Фотоархив на телефоне и в трёх облаках — это не архив, а хаос, из которого ничего не найти. PhotoPrism решает эту задачу локально: индексирует фото, распознаёт объекты и лица через ИИ, строит поиск по содержимому снимка — и всё это на вашем сервере, без подписок и чужих серверов с вашими семейными фото. Ниже — рабочий docker-compose.yml, с которым сервис поднимается за 10 минут.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое PhotoPrism и когда он лучше Immich

PhotoPrism — self-hosted фотоменеджер с автоматическим тегированием через TensorFlow: он сам находит на фото людей, животных, еду, пейзажи, документы и создаёт по ним поисковые теги без ручной разметки. По интерфейсу это ближе к Google Photos, чем к файловому менеджеру — карта съёмок, хронология, альбомы, поиск по тексту вроде «пляж 2024».

Ключевое отличие от Immich — модель хранения. PhotoPrism работает поверх существующей файловой структуры: вы кладёте файлы в папку originals как угодно (по годам, по событиям), а PhotoPrism её индексирует, не трогая оригиналы и не перекладывая их в свою БД. Это удобно, если у вас уже есть архив, синхронизированный через rsync или Syncthing, и вы не хотите отдавать структуру файлов приложению. Immich в этом смысле более «мобильный» — заточен под автозагрузку с телефона и по UX ощущается динамичнее, но глубже интегрирует файлы в свою модель.

Что учитывать при выборе:

КритерийPhotoPrismImmich
Модель храненияИндексирует внешнюю структуру папокИмпортирует в свою библиотеку
Мобильное приложениеЕсть, но менее зрелоеСильная сторона, активно развивается
ИИ-тегиTensorFlow, работает из коробкиML-теги и распознавание лиц, требует больше ресурсов
Зрелость проектаСтабилен, развивается медленнееБыстрые релизы, иногда breaking changes
Порог входаНиже, меньше сервисов в стекеВыше, больше контейнеров (Redis, ML-сервис)

Если вам важно не менять структуру хранения фото и получить предсказуемый, редко ломающийся сервис — берите PhotoPrism. Если нужен полноценный аналог Google Photos с автозагрузкой с телефона — Immich, скорее всего, удобнее.

Требования к серверу

PhotoPrism использует TensorFlow для распознавания объектов, и это самая ресурсоёмкая часть — индексация большого архива нагружает CPU на всех ядрах на время работы. Ориентировочно:

  • CPU — от 2 ядер, для комфортной индексации архивов от 10 000 фото лучше 4.
  • RAM — от 2 ГБ хватит для запуска, но на практике с MariaDB и активной индексацией комфортнее с 4 ГБ и больше. Это ориентир, не измеренное значение — зависит от размера библиотеки и настроек кеша БД.
  • Диск — под сам PhotoPrism немного, но нужно место под оригиналы фото и under sidecar-файлы (XMP), плюс кеш превью — рассчитывайте с запасом.
  • Docker и Docker Compose — если ещё не установлены, разверните по инструкции установки Docker на Ubuntu 24.04.

Архитектурно важно: если сервер будет обрабатывать фото ARM-совместимо (например, недорогой ARM-инстанс), учтите нюансы — PhotoPrism официально поддерживает ARM64-образы, но некоторые модули TensorFlow на ARM работают медленнее, чем на x86. Подробнее про сами особенности контейнеров на ARM — в статье про Docker на ARM.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Готовый docker-compose.yml

Структура каталогов перед запуском:

mkdir -p ~/photoprism/{storage,originals,import}
cd ~/photoprism

Файл docker-compose.yml:

services:
  photoprism:
    image: photoprism/photoprism:latest
    restart: unless-stopped
    depends_on:
      - mariadb
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    ports:
      - "2342:2342"
    environment:
      PHOTOPRISM_ADMIN_USER: "admin"
      PHOTOPRISM_ADMIN_PASSWORD: "СЮДА_СЛОЖНЫЙ_ПАРОЛЬ"
      PHOTOPRISM_AUTH_MODE: "password"
      PHOTOPRISM_SITE_URL: "https://photos.example.com/"
      PHOTOPRISM_DISABLE_TLS: "false"
      PHOTOPRISM_DEFAULT_TLS: "true"
      PHOTOPRISM_ORIGINALS_LIMIT: "5000"
      PHOTOPRISM_HTTP_COMPRESSION: "gzip"
      PHOTOPRISM_LOG_LEVEL: "info"
      PHOTOPRISM_READONLY: "false"
      PHOTOPRISM_EXPERIMENTAL: "false"
      PHOTOPRISM_DISABLE_CHOWN: "false"
      PHOTOPRISM_DISABLE_WEBDAV: "false"
      PHOTOPRISM_DISABLE_SETTINGS: "false"
      PHOTOPRISM_DISABLE_TENSORFLOW: "false"
      PHOTOPRISM_DISABLE_FACES: "false"
      PHOTOPRISM_DISABLE_CLASSIFICATION: "false"
      PHOTOPRISM_DISABLE_VECTORS: "false"
      PHOTOPRISM_DARKTABLE_PRESETS: "false"
      PHOTOPRISM_DETECT_NSFW: "false"
      PHOTOPRISM_UPLOAD_NSFW: "true"
      PHOTOPRISM_DATABASE_DRIVER: "mysql"
      PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
      PHOTOPRISM_DATABASE_NAME: "photoprism"
      PHOTOPRISM_DATABASE_USER: "photoprism"
      PHOTOPRISM_DATABASE_PASSWORD: "СЮДА_ПАРОЛЬ_БД"
      PHOTOPRISM_SITE_TITLE: "Мой фотоархив"
      PHOTOPRISM_SITE_CAPTION: "Семейные фото"
      UID: "1000"
      GID: "1000"
      UMASK: "0002"
    working_dir: "/photoprism"
    volumes:
      - "./originals:/photoprism/originals"
      - "./import:/photoprism/import"
      - "./storage:/photoprism/storage"

  mariadb:
    image: mariadb:11
    restart: unless-stopped
    security_opt:
      - seccomp:unconfined
      - apparmor:unconfined
    command: >-
      mariadbd
      --innodb-buffer-pool-size=512M
      --transaction-isolation=READ-COMMITTED
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --max-connections=512
      --innodb-rollback-on-timeout=OFF
      --innodb-lock-wait-timeout=120
    volumes:
      - "./database:/var/lib/mysql"
    environment:
      MARIADB_AUTO_UPGRADE: "1"
      MARIADB_INITDB_SKIP_TZINFO: "1"
      MARIADB_DATABASE: "photoprism"
      MARIADB_USER: "photoprism"
      MARIADB_PASSWORD: "СЮДА_ПАРОЛЬ_БД"
      MARIADB_ROOT_PASSWORD: "СЮДА_ROOT_ПАРОЛЬ"

Пароли — обязательно замените на свои, одинаковые в блоках photoprism и mariadb для PHOTOPRISM_DATABASE_PASSWORD / MARIADB_PASSWORD. Не оставляйте дефолтные значения из примеров в интернете — база с паролем "insecure" на сервере с открытым портом это прямой путь к компрометации.

Переменные окружения: что реально важно настроить

Из полусотни переменных PhotoPrism в реальной эксплуатации важны единицы:

  • PHOTOPRISM_SITE_URL — публичный адрес, под которым сервис будет доступен. Если сайт открывается по другому URL, чем указан здесь, будут ломаться превью и WebDAV.
  • PHOTOPRISM_ORIGINALS_LIMIT — лимит размера файла в мегабайтах на загрузку (5000 = 5 ГБ, с запасом под видео с телефона).
  • PHOTOPRISM_DISABLE_TENSORFLOW — если true, отключает ИИ-распознавание объектов полностью. Оставляйте false, ради этого всё и затевалось.
  • PHOTOPRISM_DISABLE_FACES — то же самое для распознавания лиц. Учтите: распознавание лиц требует больше вычислений и памяти на этапе индексации.
  • PHOTOPRISM_READONLY — включите true, если хотите, чтобы PhotoPrism только индексировал и показывал фото, но не мог их удалять/перемещать через веб-интерфейс — полезно, если originals синхронизируются извне (Syncthing, rclone).
  • UID/GID — выставьте под владельца папки originals на хосте, иначе будут проблемы с правами на чтение/запись файлов и XMP-сайдкаров.

Полный список переменных можно посмотреть в официальной документации проекта — здесь приведены только те, что реально влияют на поведение в 95% случаев.

Запуск, первичный вход и индексация

Поднимаем стек:

docker compose up -d
docker compose logs -f photoprism

Первый запуск MariaDB создаёт БД — подождите, пока в логах не появится строка о старте веб-сервера на порту 2342. Дальше:

  1. Откройте http://IP-сервера:2342 (или домен, если уже настроен reverse-proxy).
  2. Войдите под admin и паролем из PHOTOPRISM_ADMIN_PASSWORD.
  3. Скопируйте фото в папку ~/photoprism/originals (или import, если хотите, чтобы PhotoPrism сам их разложил по годам).
  4. В интерфейсе зайдите в Library → Index и запустите индексацию.

Индексация — самый тяжёлый по CPU этап: PhotoPrism прогоняет каждое фото через TensorFlow, извлекает EXIF, строит превью нескольких размеров. На архиве в несколько тысяч фото процесс может идти от десятков минут до нескольких часов в зависимости от мощности сервера и настроек — точное время у вас будет своё, ориентироваться на чужие цифры бессмысленно. После первого прохода последующие индексации новых файлов идут быстро, так как обрабатываются только новые снимки.

Если сервер перезагружается или контейнер падает во время долгой индексации — это штатно обрабатывается, PhotoPrism просто продолжит с недообработанных файлов при следующем запуске индексации.

Доступ по HTTPS через reverse-proxy

Открывать PhotoPrism напрямую по IP и порту 2342 в проде не стоит — нужен нормальный TLS и домен. Проще всего добавить его как ещё один сервис за уже развёрнутым reverse-proxy. Если у вас ещё нет прокси перед контейнерами, разверните Traefik по инструкции для Docker — он сам получает сертификаты Let's Encrypt и не требует ручной настройки nginx.

Пример добавления лейблов Traefik в сервис photoprism (вместо публикации порта наружу):

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.photoprism.rule=Host(`photos.example.com`)"
      - "traefik.http.routers.photoprism.entrypoints=websecure"
      - "traefik.http.routers.photoprism.tls.certresolver=le"
      - "traefik.http.services.photoprism.loadbalancer.server.port=2342"
    networks:
      - traefik-net

При этом строку ports: - "2342:2342" из основного файла лучше убрать — порт наружу открывает Traefik, контейнеру PhotoPrism публиковать порт напрямую больше не нужно. Не забудьте подключить сеть traefik-net (или как она называется в вашей конфигурации Traefik) и указать в PHOTOPRISM_SITE_URL итоговый HTTPS-адрес — иначе будут проблемы с CORS и WebDAV-клиентами.

Бэкапы: что действительно нужно сохранять

У PhotoPrism три источника данных, и терять нельзя ни один:

  • originals/ — сами фото и видео. Это главное, без чего архив теряется безвозвратно.
  • База MariaDB (./database) — альбомы, теги, лица, метаданные, история изменений. Восстановить можно переиндексацией originals, но все ручные правки (альбомы, избранное, распознанные лица) потеряются.
  • storage/ — кеш превью, конфиги, сертификаты. Пересоздаётся автоматически, бэкапить не обязательно.

Минимальная стратегия бэкапа: rsync или rclone для originals на отдельное хранилище (в идеале — за пределы этого же сервера) плюс регулярный дамп MariaDB:

docker compose exec mariadb mariadb-dump -u photoprism -p photoprism > backup_$(date +%F).sql

Если нужен полноценный автоматизированный бэкап Docker-томов с ротацией — посмотрите инструкцию по бэкапу Docker volume, схему из неё можно применить и к database, и к originals. Для действительно больших фотоархивов подойдёт связка с restic в Docker Compose — инкрементальные бэкапы с шифрованием и дедупликацией куда экономнее по месту, чем полные копии каждый раз.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

PhotoPrism бесплатный?

Основной функционал (индексация, ИИ-теги, поиск, альбомы) open-source и бесплатен. Есть платная подписка Plus/Team с дополнительными возможностями (например, расширенные права доступа для команд), но для личного архива она не обязательна.

Нужна ли видеокарта для ИИ-распознавания?

Нет, TensorFlow в PhotoPrism по умолчанию работает на CPU. GPU-ускорение существует, но для домашнего архива в CPU-режиме скорости достаточно — просто индексация большого архива займёт больше времени.

Можно ли перенести уже существующую папку с фото, ничего не удаляя?

Да, это и есть основной сценарий использования — смонтируйте существующую папку как originals (read-only через PHOTOPRISM_READONLY: "true", если не хотите, чтобы PhotoPrism что-то менял) и запустите индексацию.

Что делать, если индексация зависает на одном файле?

Обычно это повреждённый файл или неподдерживаемый формат/кодек. Смотрите docker compose logs -f photoprism — там будет видно, на каком файле застряло, и можно исключить его из originals.

Как обновить PhotoPrism без потери данных?

docker compose pull && docker compose up -d — данные хранятся в смонтированных папках, а не внутри контейнера, поэтому обновление образа их не затрагивает. Перед крупными обновлениями всё же стоит сделать дамп БД.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →