Приложение для фото и видео Immich

На мой взгляд это лучшее приложения для хранения и синхронизации своего фото и видео. Можно послать далеко и надолго все остальные сервисы, (не буду называть их имен, они и так известны), которые по мимо вытягивания бабла еще и используют наши же файлы в своих интересах. Это просто бомба, все файлы с телефона или из других источников будут упорядоченно хранится на своем собственном сервере. Неограниченны в размерах файлохранилища. И главные фишки - машинный поиск и распознавание лиц. Меня старенького ИИ распознал в детсадовском возрасте. Вот с поиском бывают некоторые смешные курьёзы, но это фича, а не баг, как говорится 😆

Для приобретения нового опыта установки и способов хранения и синхронизации своего видео и фото, без громоздких аналогов попробую сначала установить данное приложение на виртуальную машину, что бы не допустить ошибок при установке на реальное железо. Почитать о данном приложении

Установка Docker compose

Docker compose

Установка Immich

Docker Compose — рекомендуемый метод запуска Immich в производстве. Ниже приведены шаги по развертыванию Immich с помощью Docker Compose. Официальный источник

Шаг 1. Загрузите необходимые файлы.

Создайте каталог по вашему выбору (например, ./Immich-app), чтобы удерживать docker-compose.yml и .env файлы. В созданном каталоге будет хранится все данные фото и видео по умолчанию. Поэтому лучше установить на более объемный диск. Перейдите в созданный вами каталог:

mkdir ./Immich-app
cd ./Immich-app

Скачать docker-compose.yml и example.env , либо выполнив следующие команды:

Получите файл docker-compose.yml.:

wget https://github.com/Immich-app/Immich/releases/latest/download/docker-compose.yml

Получить файл .env:

wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

(Необязательно) Получите файл hwaccel.yml:

wget https://github.com/Immich-app/Immich/releases/latest/download/hwaccel.yml

Шаг 2. Заполните файл .env пользовательскими значениями.

nano example.env
# Вы можете найти документацию для всех поддерживаемых переменных env по адресу https://Immich.app/docs/install/environment-variables.

# Место, где хранятся загруженные вами файлы
UPLOAD_LOCATION=./library

# Используемая версия Immich.  Вы можете привязать это к конкретной версии, например «v1.71.0».
Immich_VERSION=release

# Секрет соединения для postgres.  Вам следует изменить его на случайный пароль.
DB_PASSWORD=postgres

# Значения ниже этой строки менять не нужно
###################################################################################
DB_HOSTNAME=Immich_postgres
DB_USERNAME=postgres
DB_DATABASE_NAME=Immich

REDIS_HOSTNAME=Immich_redis

Сохранить файл Ctrl+O Enter, закрыть Ctrl+X

  • При необходимости заполните информацию о пользовательской базе данных.
  • Заселить UPLOAD_LOCATIONс предпочтительным местом для хранения резервных ресурсов.
  • Рассмотрите возможность изменения DB_PASSWORDк чему-то случайно сгенерированному

Шаг 3 — Запустите контейнеры Immich

Из каталога, который вы создали на шаге 1 (который теперь должен содержать ваши настроенные docker-compose.yml и .env файлы)

Запустите контейнеры с помощью команды docker compose:

docker compose up -d

Получил ошибку:

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3DImmich%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied

Запускать через sudo

sudo docker compose up -d

Шаг 4 – Обновление Immich

Что бы обновить приложение надо перейти в каталог с конфигами докера куда он установлен cd /home/sklad/Immich-app/

Обязательно обновить файл конфигурации, переименовать и удалить старый файл на всяк случай sudo mv docker-compose.yml docker-compose.yml.$(date +%d-%m-%Y).bak

Скачать последнюю версию конфига: sudo wget https://github.com/Immich-app/Immich/releases/latest/download/docker-compose.yml

Обновить докер: sudo docker compose pull && sudo docker compose up -d

И на всякий случай перезапустить докер: docker compose restart но это не обязательно.

ps А то обновил бездумно, потом капал рыл в чем проблема, а в мануале про это не сказано. В дискорде написали , что нужно читать про обновления там все написано, что нужны некоторые танцы без бубна. Так что обязательно читать, что пишут про обновленную версию. А выходят они с завидной регулярностью. Как они себе поставили планку релиз раз в неделю. Или пока не начнутся какие то косяки в телефоне, поскольку в телефоне то все автоматом обновляется, а серверная часть ручками и может возникнуть конфликт версий. Так я дотянул с версией 1.95 до выпуска 1.98 пропустив кучу релизов, пока мне не сказали домашние, где наши фотки, что за хрень? 😆

Backup Immich резервное копирование

Подключиться к серверу по SSH перейти в каталог с установкой cd /home/sklad/Immich-app/

База данных

Выполнить команду копирования базы данных

docker exec -t immich_postgres pg_dumpall -c -U postgres --if-exists > /home/sklad/backup/immich/`date +'%d%m%Y'`-immich-dump.sql
  1. docker exec -t immich_postgres
  • docker exec — позволяет запускать команды внутри уже запущенного контейнера.
  • -t — опция для выделения псевдотерминала. Она делает возможным интерактивный вывод команд, что особенно полезно для таких команд, как psql и pg_dumpall.
  • immich_postgres — это имя контейнера, внутри которого выполняется команда.
  1. pg_dumpall
  • pg_dumpall — это утилита PostgreSQL, которая делает полный дамп всей базы данных (всех баз данных) в одном файле. Она используется для создания резервной копии всех баз данных, а также глобальных объектов, таких как роли и привилегии.
  1. -c
  • -c (или --clean) — ключ, указывающий, что при восстановлении из дампа сначала нужно удалить (очистить) существующие объекты, если они уже существуют, перед их повторным созданием. Это полезно для предотвращения конфликта имен при восстановлении данных.
  1. -U postgres
  • -U postgres — указывает имя пользователя PostgreSQL, под которым будет выполнен дамп. В данном случае используется пользователь postgres, который является суперпользователем PostgreSQL.
  1. --if-exists
  • --if-exists — добавляет к команде очистки конструкцию IF EXISTS. Это означает, что если объект (таблица, схема и т.д.) уже существует в базе данных, он будет удален, но если объекта нет — ошибка не будет выдана. Это полезно для безопасного восстановления дампа, чтобы не возникали ошибки, если объект не существует.
  1. > /home/sklad/backup/immich/$(date +'%d%m%Y')-immich-dump.sql
  • > — перенаправление вывода. Результат выполнения команды будет записан в указанный файл.
  • /home/sklad/backup/immich/$(date +'%d%m%Y')-immich-dump.sql — путь к файлу, в который будет сохранен дамп базы данных. Команда $(date +'%d%m%Y') добавляет к имени файла текущую дату в формате ддммгггг (например, 09102024).

Восстановление базы данных:

cat "/home/sklad/backup/immich/immich-dump.sql" \
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
| docker exec -i immich_postgres psql --username=postgres

Эта команда выполняет восстановление базы данных из дампа с внесением изменения в дамп перед его применением. Вот пошаговый разбор того, что происходит:

  1. cat "/home/sklad/backup/immich/immich-dump.sql"
  • cat — команда, которая выводит содержимое указанного файла на стандартный вывод.
  • "/home/sklad/Immich-app/immich-dump.sql" — путь к файлу дампа базы данных, который был ранее создан с помощью pg_dumpall.

Эта часть команды читает содержимое дампа базы данных, чтобы передать его дальше через пайплайн.

  1. | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g"
  • | (пайп) — передает вывод предыдущей команды (cat) как ввод для следующей команды.

  • sed — это утилита для поиска и замены текста в потоке данных.

    В данном случае sed выполняет следующую операцию:

    • Ищет в дампе строку SELECT pg_catalog.set_config('search_path', '', false);
    • Заменяет её на строку SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);
    • /g — глобальная замена, которая означает, что замена будет применена ко всем вхождениям этой строки, а не только к первому найденному.

Это необходимо для того, чтобы явно указать схему public и pg_catalog как часть пути поиска в базе данных при восстановлении.

  1. | docker exec -i immich_postgres psql --username=postgres
  • | — опять же, пайп, который передает отредактированный дамп (после изменений sed) следующей команде.
  • docker exec -i immich_postgres psql --username=postgres:
    • docker exec — выполняет команду внутри запущенного контейнера Docker. В данном случае команда выполняется в контейнере immich_postgres.
    • -i — включает режим интерактивного ввода (чтобы команда могла читать данные с входного потока).
    • psql --username=postgres — запускает команду psql (интерфейс командной строки для PostgreSQL), используя пользователя postgres. Эта команда ожидает SQL-запросы на входе, которые она будет выполнять в базе данных.

Таким образом, финальная команда:

  1. Читает содержимое дампа из файла immich-dump.sql.
  2. Заменяет в дампе определенные SQL-команды с помощью sed.
  3. Восстанавливает базу данных в контейнере PostgreSQL immich_postgres с использованием измененного дампа.

Файлы

Резервное копирование необходимо только исходного содержимого, которое хранится в следующих папках:

  1. UPLOAD_LOCATION/library
  2. UPLOAD_LOCATION/upload
  3. UPLOAD_LOCATION/profile

Удаление образов, не привязанных к контейнеру

После множества обновлений обнаружил, что есть образы, которые просто занимают место и не используются.

Посмотреть список не используемых образов:

docker images -f dangling=true

Удалить неиспользуемые образы:

docker image prune

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]

Подтвердить удаление Y

Удаление несвязанных томов

Список томов:

docker volume ls

Удаление томов:

docker volume prune

WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N]

Подтвердить удаление Y

Вход в приложение Immich

Войдите в веб-приложение по адресу http://<machine-ip-address>:2283 и нажмите кнопку «Начало работы».

Пример конфигурации Apache

Ниже приведен пример конфигурации сайта Apache2. Обыкновенный обратный прокси. Имя сервера свое.

<VirtualHost *:80>
    ServerName <snip>

    ProxyRequests off
    ProxyVia on

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/api/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*)           ws://localhost:2283/$1 [P,L]

    ProxyPass        /api/socket.io ws://localhost:2283/api/socket.io
    ProxyPassReverse /api/socket.io ws://localhost:2283/api/socket.io

    <Location />
        ProxyPass http://localhost:2283/
        ProxyPassReverse http://localhost:2283/
    </Location>
</VirtualHost>

Ответы на другие вопросы

Все оставшиеся вопросы и ответы на них найдутся в документации

Установка на железо

Зайти на сервер по ssh

Зайти под пользователя рут или через sudo и сделать все шаги по установке написанные выше при установке на виртуалку.

Войдите в веб-приложение по адресу http://<machine-ip-address>:2283 и нажмите кнопку «Начало работы».

Вход через домен

Создать домен для приложения photo.wildserver.ru

Создать два виртуальных хоста один для 80 порта с редиректом на защищенное соединение по 443 порту с такими конфигами (взято с рабочей машины):

sudo nano photo.wildserver.ru.conf

<VirtualHost *:80>
	ServerAdmin admin@wildserver.ru
    ServerName photo.wildserver.ru
    ServerAlias www.photo.wildserver.ru
    CustomLog ${APACHE_LOG_DIR}/photo.wildserver.ru.access.log combined
    ErrorLog ${APACHE_LOG_DIR}/photo.wildserver.ru.error.log

RewriteEngine on
RewriteCond %{SERVER_NAME} =www.photo.wildserver.ru [OR]
RewriteCond %{SERVER_NAME} =photo.wildserver.ru
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Сохранить файл Ctrl+O Enter, закрыть Ctrl+X

sudo nano photo.wildserver.ru.80-443.proxy.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerAdmin admin@wildserver.ru
  ServerName photo.wildserver.ru
  ServerAlias www.photo.wildserver.ru
    CustomLog ${APACHE_LOG_DIR}/photo.wildserver.ru.access.log combined
    ErrorLog ${APACHE_LOG_DIR}/photo.wildserver.ru.error.log
  SSLEngine On
  SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerName off
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/photo.wildserver.ru/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/photo.wildserver.ru/privkey.pem
  ProxyRequests Off
  ProxyPreserveHost Off
  ProxyVia on

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/api/socket.io            [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /(.*)           ws://localhost:2283/$1 [P,L]

    ProxyPass        /api/socket.io ws://localhost:2283/api/socket.io
    ProxyPassReverse /api/socket.io ws://localhost:2283/api/socket.io

  <Location />
    ProxyPass http://localhost:2283/
    ProxyPassReverse http://localhost:2283/
  </Location>

</VirtualHost>
</IfModule>

Сохранить файл Ctrl+O Enter, закрыть Ctrl+X

При таком раскладе как бы не обращались к серверу всегда будет происходить перенаправление на зашифрованное соединение.

Для работы должен быть получен сертификат Let’s Encrypt.

Домен и сертификат были заранее получены. пришлось изменить только конфиг виртуального хоста.

После всего хранилище фото и видео доступно по адресу photo.wildserver.ru

Настройка переменных среды

Сделал некоторые изменения для использования большего количества памяти, железо позволяет. Осталось применить настройки.


# *1: При изменении уровней параллелизма службы машинного обучения рекомендуется начинать с этого параметра,
# а затем настраивать остальные.
# Число потоков пула потоков запроса (отключено, если <= 0) 
# количество ядер процессора

MACHINE_LEARNING_REQUEST_THREADS=2 # НЕ ПРЕВЫШАТЬ ЧИСЛО РЕАЛЬНЫХ ПРОЦЕССОРОВ

# *2: Поскольку каждый процесс дублирует модели в памяти, менять это не рекомендуется, 
# если у вас нет достаточного объема памяти. 
# Количество рабочих процессов для создания 1

MACHINE_LEARNING_WORKERS=4

#########################################################################################
#								ОСТОРОЖНО											                                        	#
#																						                                            #
# Чтобы изменить переменные среды, необходимо заново создать контейнеры Иммиха.			    #
# Простой перезапуск контейнеров не заменяет среду внутри контейнера!					          #
#																						                                            #
# Чтобы воссоздать контейнер с помощью Docker Compose, запустите docker compose up -d.	#
# В большинстве случаев докер распознает, что .env файл изменился и заново создайте		  #
# затронутые контейнеры.																                                #
# Если это не сработает, попробуйте запустить docker compose up -d --force-recreate.	  #
#																						                                            #
#########################################################################################

Мобильное приложение

https://immich.app/docs/features/mobile-app

Ошибки и их устранение

Server status offline

Статус сервера офлайн, такая надпись в нижнем левом углу бывает высвечивается. Лечится перезапуском контейнера.

cd /home/sklad/Immich-app/
sudo docker compose up -d

При обновлении ошибка

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json?all=1&filters=%7B%22label%22%3A%7B%22com.docker.compose.config-hash%22%3Atrue%2C%22com.docker.compose.project%3Dimmich%22%3Atrue%7D%7D": dial unix /var/run/docker.sock: connect: permission denied

Лечится то же перезапуском.

Время в контейнере и на хосте не совпадает

https://ru.stackoverflow.com/questions/1363305/docker-%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%B8-%D0%B2-%D0%BA%D0%BE%D0%BD%D1%82%D0%B5%D0%B9%D0%BD%D0%B5%D1%80%D0%B5-%D1%81-%D1%85%D0%BE%D1%81%D1%82%D0%BE%D0%BC