SSD Nodes Learn
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-07-19

Héberger Immich : votre propre Google Photos

Hébergez Immich sur un VPS avec le Docker Compose officiel : serveur, recherche ML, Postgres, sauvegarde mobile, HTTPS, mises à jour et sauvegardes sûres.

Ce que vous allez construire

Immich est un service de sauvegarde de photos et de vidéos auto-hébergé, un véritable remplaçant de Google Photos. Il propose une application mobile qui téléverse votre pellicule en arrière-plan, une frise chronologique, des albums, la reconnaissance des visages et une recherche par apprentissage automatique qui trouve « plage » ou une personne sans que vous ayez jamais rien étiqueté. Vous l'exécutez sur un VPS qui vous appartient, les fichiers originaux restent sur votre disque, et personne ne les analyse pour vous vendre des choses.

L'installation, c'est quatre conteneurs issus du fichier Docker Compose du projet lui-même. Cette partie prend dix minutes. Le reste de ce guide, c'est là que se cache la difficulté : le conteneur d'apprentissage automatique est gourmand en mémoire sur une petite machine, les originaux remplissent vite le disque, l'application mobile refuse un serveur en simple HTTP, et Immich publie assez souvent des changements incompatibles pour qu'un docker compose pull négligent laisse votre base de données incapable de démarrer. Prenez ces quatre points au sérieux et Immich est d'une solidité à toute épreuve. Ignorez-les et vous perdrez un week-end.

Prérequis, et les pièges à connaître honnêtement

  • RAM : la documentation officielle indique 6 Go au minimum et 8 Go recommandés, considérez 4 Go plus le swap comme le plancher absolu. Les conteneurs immich-server et Postgres sont modestes. Le conteneur immich-machine-learning est le glouton : il charge les modèles CLIP et de reconnaissance faciale en RAM pour construire les index de recherche, et sur une machine de 2 Go le noyau le tue. Ajoutez du swap même si vous avez 4 Go.
  • Disque : dimensionnez-le pour toute votre bibliothèque, puis un peu plus. Vos originaux sont copiés intégralement, et en plus Immich génère des miniatures et des images d'aperçu (environ 10 à 20 % en supplément). Une collection de photos de 200 Go réclame un volume de 300 Go. Postgres est petit en comparaison.
  • CPU : n'importe quel VPS KVM moderne convient, mais le ML sur CPU est lent. L'indexation de recherche intelligente d'une grosse importation peut tourner pendant des heures en arrière-plan. C'est normal ; cela ne nécessite pas de GPU.
  • Un nom de domaine pointant vers le VPS. L'application mobile préfère nettement un point d'accès HTTPS, et vous voudrez un proxy inverse devant. C'est le même type de configuration qu'une instance Nextcloud auto-hébergée avec Docker, TLS et sauvegardes : Immich est l'équivalent photos de ce serveur de fichiers.
  • Docker et le plugin Compose installés, à savoir Docker Engine plus le plugin Compose v2 du dépôt apt officiel de Docker, exactement comme décrit dans notre guide des bases de Docker Compose.

Étape 1 : Ajouter du swap avant toute chose

La panne Immich la plus fréquente sur un petit VPS, c'est le conteneur ML tué par l'OOM (mémoire insuffisante). Donnez d'abord au noyau un peu d'air pour respirer.

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

free -h doit maintenant afficher une ligne Swap: de 4.0Gi. Cela ne rendra pas le ML rapide, mais cela empêche le conteneur de mourir en pleine indexation sur une machine de 4 Go.

Étape 2 : Récupérer le compose et l'env officiels, les leurs et pas une copie

Immich fige les versions de ses services et, point crucial, l'image de sa base de données à l'intérieur des fichiers qu'il livre. Ne collez pas un fichier compose issu d'un blog (celui-ci compris) comme source de vérité. Téléchargez les fichiers de la version publiée :

sudo mkdir -p /opt/immich && cd /opt/immich
sudo wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
sudo wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

Ils proviennent de la version marquée (tag), donc les références d'images correspondent. Le fichier compose définit quatre services, et il est utile de savoir à quoi sert chacun avant de toucher à quoi que ce soit :

  • immich-server (ghcr.io/immich-app/immich-server, conteneur immich_server) : l'API et l'interface web, à l'écoute sur le port 2283. Il monte vos téléversements sur /data.
  • immich-machine-learning (ghcr.io/immich-app/immich-machine-learning, conteneur immich_machine_learning) : recherche CLIP et reconnaissance faciale. Met en cache les modèles téléchargés dans un volume model-cache. C'est celui qui est gourmand en mémoire.
  • database (conteneur immich_postgres) : Postgres avec l'extension vectorielle VectorChord, qui alimente la recherche par similarité. Le tag de l'image est figé par empreinte (digest) directement dans le fichier compose, par exemple ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:.... Les anciennes installations utilisaient pgvecto.rs ; sa prise en charge a été supprimée dans Immich v3.0, donc tout ce que vous installez aujourd'hui est VectorChord. Ne modifiez jamais ce tag à la main.
  • redis (conteneur immich_redis) : une instance Valkey/Redis pour les files d'attente de tâches.

Étape 3 : Configurer .env, où vivent vos photos et votre base de données

Ouvrez .env et réglez quatre choses. Tout ce qui se trouve sous la ligne marquée reste tel quel.

# Where original uploads are stored on the host
UPLOAD_LOCATION=/opt/immich/library

# Where the Postgres data lives. NEVER put this on an NFS/network share.
DB_DATA_LOCATION=/opt/immich/postgres

# "v3" is a floating tag that tracks the latest v3.x. Pin a full tag like
# v3.0.2 instead — then you upgrade on purpose, not by surprise.
IMMICH_VERSION=v3.0.2

# Change this to a long random string. Letters and digits only.
DB_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_STRING

# Set your timezone so timestamps and "on this day" line up
TZ=Europe/London

###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

Deux règles qui vous éviteront des ennuis. UPLOAD_LOCATION doit pointer vers votre gros disque : si vous attachez un volume de données plus tard, réglez ceci dès le départ sur son point de montage, car le déplacer après coup revient à déplacer les miniatures et à mettre à jour les chemins des fichiers. Et DB_DATA_LOCATION doit être sur un disque local : Postgres sur un partage NFS ou SMB se corrompt, et la documentation le dit en toutes lettres. Si vous n'utilisez que des lettres et des chiffres dans DB_PASSWORD, vous évitez toute une catégorie de bugs d'échappement dans la chaîne de connexion.

Étape 4 : Premier démarrage et création de l'utilisateur administrateur

cd /opt/immich
sudo docker compose up -d
sudo docker compose ps

Un résultat correct, c'est quatre conteneurs, tous running et à terme healthy :

NAME                      STATUS
immich_machine_learning   Up (healthy)
immich_postgres           Up (healthy)
immich_redis              Up (healthy)
immich_server             Up (healthy)

Le premier up télécharge plusieurs gigaoctets d'images, alors laissez-lui le temps. Suivez la progression avec sudo docker compose logs -f immich-server ; le serveur indique dans ses journaux qu'il écoute sur le port 2283 une fois prêt. Ouvrez maintenant http://YOUR_SERVER_IP:2283 dans un navigateur. La première visite affiche un assistant Getting Started : le premier compte que vous créez est l'administrateur. Choisissez un mot de passe fort ; ce compte possède les réglages du serveur, la gestion des utilisateurs et la configuration ML dont vous aurez besoin plus tard.

Étape 5 : L'application mobile et la sauvegarde en arrière-plan

Installez « Immich » depuis l'App Store ou le Play Store. Sur l'écran de connexion, elle demande une Server Endpoint URL (URL du point d'accès du serveur). Saisissez l'URL complète, schéma compris, par exemple https://photos.example.com (l'application ajoute /api elle-même). Connectez-vous avec le compte que vous venez de créer, puis ouvrez l'écran Backup de l'application, choisissez les albums à protéger (généralement Appareil photo et Captures d'écran), et activez la Background backup (sauvegarde en arrière-plan). La sauvegarde en arrière-plan sous iOS est bridée par le système : les téléversements au premier plan s'exécutent toujours, ceux en arrière-plan ont lieu quand le système l'autorise.

C'est exactement là que les gens se retrouvent bloqués, alors lisez l'étape 6 avant de vous battre avec l'application.

Étape 6 : HTTPS via un proxy inverse, et la règle de l'URL complète

L'application mobile veut vraiment du HTTPS. Placez un proxy inverse devant le port 2283 et terminez le TLS à cet endroit. Si vous exécutez déjà plusieurs conteneurs, Traefik avec TLS automatique pour plusieurs applications Docker est l'option la plus propre : un seul bloc d'étiquettes (labels) route photos.example.com vers le conteneur immich-server et récupère le certificat pour vous. Si vous préférez nginx, le guide Let's Encrypt avec Certbot et nginx vous obtient un certificat et un bloc proxy_pass http://127.0.0.1:2283;. Un réglage du proxy compte pour Immich : augmentez la limite de taille de téléversement, car les vidéos de téléphone sont volumineuses. Sous nginx, c'est client_max_body_size 50000M; dans le bloc server ; la valeur par défaut de 1 Mo rejette les téléversements de vidéos avec 413 Request Entity Too Large.

La règle que l'application impose : le point d'accès doit être joignable et, en pratique, doit être en HTTPS. Les points d'accès en http://, ou une IP directe avec le port omis, sont l'origine du « l'application ne peut pas joindre le serveur », traité comme panne nommée plus bas.

Étape 7 : Bibliothèques externes contre téléversements, importer une arborescence de photos existante

Il y a deux façons pour les photos d'entrer dans Immich, et ce n'est pas la même chose.

  • Les téléversements sont des éléments qu'Immich possède. L'application ou le téléverseur web copie le fichier dans UPLOAD_LOCATION. Immich peut les renommer, les déplacer et les supprimer.
  • Les bibliothèques externes sont des imports en lecture seule de fichiers qui se trouvent déjà dans un dossier de votre serveur : une ancienne arborescence Pictures, un export de NAS. Immich les indexe sur place et les affiche dans la frise chronologique, mais ne modifie ni ne supprime jamais les originaux.

Pour importer une arborescence existante, montez-la en lecture seule dans le conteneur serveur. Modifiez docker-compose.yml sous immich-server: et ajoutez un volume :

  immich-server:
    volumes:
      - ${UPLOAD_LOCATION}:/data
      - /etc/localtime:/etc/localtime:ro
      - /srv/photos:/mnt/media/photos:ro

Le :ro garantit qu'Immich ne peut jamais toucher aux originaux. Recréez le conteneur avec sudo docker compose up -d, puis dans l'interface web allez sur votre avatar → Administration → External Libraries → Create Library, choisissez l'utilisateur propriétaire, cliquez sur Add sous Folders, et saisissez le chemin du conteneur, à savoir /mnt/media/photos, pas le chemin de l'hôte /srv/photos. Cliquez sur Scan. Utiliser le chemin de l'hôte au lieu du chemin du conteneur est l'erreur numéro un des bibliothèques externes ; le scan ne trouve rien et signale zéro élément.

Étape 8 : La discipline de mise à jour qu'Immich exige

C'est la partie qui distingue un Immich heureux d'un Immich cassé. Immich publie vite et ne rétroporte pas les correctifs ni ne prend en charge les rétrogradations. Suivre aveuglément le tag flottant v3 finira par casser votre base de données. La discipline :

  1. Figez une version. Gardez IMMICH_VERSION réglé sur un tag concret comme v3.0.2, pas le tag flottant v3 qui tire toujours la plus récente v3.x.
  2. Lisez les notes de version à chaque fois avant de mettre à jour. Les changements incompatibles, surtout ceux touchant la base de données ou l'extension vectorielle, y sont signalés. La version v3.0 en est l'exemple évident : elle a supprimé pgvecto.rs purement et simplement, donc quiconque était encore sur l'ancienne extension devait terminer la migration vers VectorChord (introduite dès la v1.133) avant de pouvoir monter de version.
  3. Sauvegardez d'abord la base de données (étape 9). Toujours, mais doublement quand les notes mentionnent la base de données.
  4. Prenez aussi le nouveau fichier compose. IMMICH_VERSION ne fige que les images du serveur et du ML. L'image Postgres est figée par empreinte à l'intérieur de docker-compose.yml, donc une version qui a besoin d'une extension de base de données plus récente livre un nouveau fichier compose. Retéléchargez les deux fichiers de la version, réappliquez vos valeurs .env, puis mettez à jour.
  5. Mettez à jour vos clients mobiles à peu près en même temps. Le serveur ne parle que sa version majeure correspondante, et l'application prend en charge la majeure actuelle et la précédente. Un serveur passé devant l'application affiche Your app major version is not compatible with the server! sur le téléphone jusqu'à ce que vous la mettiez à jour, donc le plus sûr est de mettre à jour l'application d'abord.

Les commandes concrètes, une fois les nouveaux fichiers en place :

cd /opt/immich
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune

Étape 9 : Sauvegardes, un export de base PLUS les originaux, et testez-le

Une sauvegarde d'Immich, c'est deux choses, et l'une sans l'autre ne sert à rien. La base de données contient la structure des albums, les visages, les index de recherche et la correspondance entre élément et fichier. Le répertoire des originaux contient les photos réelles. Restaurez l'un sans l'autre et vous obtenez soit des photos sans organisation, soit une coquille vide pointant vers des fichiers manquants.

Exportez la base de données avec pg_dump depuis l'intérieur du conteneur Postgres, la base immich précisément, pas tout le cluster :

sudo docker exec -t immich_postgres pg_dump --clean --if-exists \
  --dbname=immich --username=postgres | gzip > /opt/immich/immich-db-$(date +%F).sql.gz

Puis sauvegardez UPLOAD_LOCATION, toute l'arborescence /opt/immich/library, et en particulier ses sous-dossiers library/, upload/ et profile/, avec restic, rsync ou borg vers une autre machine ou un stockage objet. Faites la base de données d'abord et les fichiers ensuite, pour que l'export ne référence jamais une photo que la sauvegarde de fichiers n'a pas encore copiée. Les bibliothèques externes, vous les sauvegardez séparément à leur source réelle ; Immich ne les possède pas.

Maintenant la partie que tout le monde saute : testez la restauration. Une restauration doit s'exécuter sur une pile neuve dont le serveur n'a jamais démarré, sur une image Postgres dont l'extension vectorielle est compatible avec l'export, ce qui est exactement pourquoi vous n'improvisez jamais le tag de l'image de base de données. Sur une machine vierge avec le même compose et le même .env, effacez tout ancien état, démarrez uniquement la base de données, puis chargez l'export :

cd /opt/immich
sudo docker compose down -v
sudo docker compose pull
sudo docker compose create
sudo docker start immich_postgres
sleep 10
gunzip --stdout immich-db-2026-07-15.sql.gz |
  sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" |
  sudo docker exec -i immich_postgres psql --dbname=immich --username=postgres --single-transaction --set ON_ERROR_STOP=on
sudo docker compose up -d

La réécriture du search_path par sed n'est pas optionnelle sur une base VectorChord : omettez-la et la restauration s'interrompt en cours de route. Quand la pile redémarre avec vos originaux en place, ouvrez l'interface web : si vos photos et vos albums sont là, votre sauvegarde fonctionne. Si vous n'avez jamais fait cela, vous n'avez pas de sauvegarde, vous avez un espoir.

Modes de panne, avec les chaînes que vous verrez

Le conteneur ML est tué par l'OOM. sudo docker compose logs immich-machine-learning se termine brutalement, docker compose ps l'affiche en Restarting, et le code de sortie est 137. sudo dmesg | grep -i oom le confirme : Out of memory: Killed process ... (python3). Les tâches de recherche et de visages se bloquent alors. La cause, c'est trop peu de RAM pour les modèles. Correctifs, dans l'ordre : ajoutez du swap (étape 1) ; donnez plus de RAM au VPS ; ou, si vous ne le pouvez vraiment pas, désactivez le ML dans Administration → Settings → Machine Learning Settings en désactivant Smart Search et Facial Recognition : vous conservez les sauvegardes et les albums, vous perdez la recherche par contenu. Retirer le service immich-machine-learning du fichier compose a le même effet.

Postgres refuse de démarrer après une mise à jour. Le journal du serveur boucle avec une ligne du genre The database currently has VectorChord 0.5.3 activated, but the Postgres instance only has 0.4.2 available. This most likely means the extension was downgraded., ou, sur d'anciennes piles, The pgvecto.rs extension is not available in this Postgres instance.. La cause, c'est une image de base de données dont la version de l'extension est plus ancienne que celle vers laquelle vos données ont été mises à jour, presque toujours parce que le tag de l'image a été modifié à la main ou qu'un export plus récent a été restauré sur une image plus ancienne. Le correctif est d'utiliser l'image Postgres qui correspond : prenez le fichier compose de la version qui correspond à votre base de données, ne rétrogradez pas, et ne restaurez que sur une image compatible.

L'application mobile ne peut pas joindre le serveur. L'écran de connexion affiche une erreur de connexion / Server is not reachable après que vous avez saisi l'URL. Trois causes : vous avez tapé http:// là où le proxy ne sert que https:// ; vous vous êtes connecté directement au backend mais avez omis le port, donc il a tenté example.com (port 443) au lieu de example.com:2283 ; ou le proxy inverse ne transmet pas /api. Corrigez en saisissant l'URL complète https://photos.example.com et en confirmant qu'elle se charge d'abord dans un navigateur de téléphone. Si le navigateur fonctionne et pas l'application, le proxy supprime le chemin ou le certificat est auto-signé : l'application rejette les certificats non approuvés.

Plus d'espace disque en pleine importation. Les téléversements commencent à échouer, les miniatures deviennent vides, et les journaux affichent ENOSPC: no space left on device ou, du côté de Postgres, could not extend file ... No space left on device. df -h montre le volume UPLOAD_LOCATION à 100 %. C'est pourquoi vous dimensionnez le disque avant d'importer une grosse bibliothèque. Rétablissez la situation en attachant un volume plus grand, en arrêtant la pile, en déplaçant UPLOAD_LOCATION dessus, en mettant à jour .env, et en redémarrant ; ou agrandissez le disque existant si votre fournisseur le permet. Postgres peut se coincer s'il se remplit, alors libérez de l'espace et redémarrez le conteneur de base de données avant de conclure à une corruption.

FAQ

Combien de RAM et de disque Immich nécessite-t-il ?

Les prérequis officiels d'Immich sont de 6 Go de RAM au minimum et 8 Go recommandés ; 4 Go avec du swap est le plancher pratique pour une petite bibliothèque, et configurez le swap dans tous les cas, car le conteneur d'apprentissage automatique est la partie qui provoque des pics. Pour le disque, prévoyez la taille complète de votre bibliothèque plus environ 10 à 20 % pour les miniatures et aperçus générés, sur du stockage local ; ne placez jamais le répertoire de données Postgres sur un partage réseau. Si vous hésitez encore sur ce que vous allez faire tourner d'autre, le guide de ce qu'il faut auto-héberger en 2026 place l'empreinte d'Immich à côté d'autres services.

Puis-je faire tourner Immich sans GPU ?

Oui. Le conteneur d'apprentissage automatique tourne sans souci sur CPU : un GPU ne fait qu'accélérer l'indexation de la recherche intelligente et, avec la bonne variante d'image, le transcodage vidéo. Sur CPU, l'index initial d'une grosse bibliothèque peut prendre des heures en arrière-plan, mais cela ne bloque ni les sauvegardes ni la navigation. Si votre machine est trop petite pour le ML tout court, vous pouvez désactiver Smart Search et Facial Recognition dans les réglages d'administration et conserver tout le reste.

Comment mettre à jour Immich en toute sécurité ?

Figez IMMICH_VERSION sur un tag concret comme v3.0.2, lisez les notes de version avant chaque mise à jour, et sauvegardez la base de données d'abord. Comme l'image Postgres est figée dans docker-compose.yml plutôt que par IMMICH_VERSION, retéléchargez à la fois le fichier compose et example.env depuis la version cible et réappliquez vos valeurs, puis lancez docker compose pull && docker compose up -d. Ne laissez jamais la version flotter sans surveillance : Immich publie des changements incompatibles et ne prend pas en charge les rétrogradations.

Que dois-je exactement sauvegarder ?

Deux choses, ensemble : un pg_dump de la base immich et l'intégralité du répertoire des originaux UPLOAD_LOCATION. La base de données contient les albums, les visages et la correspondance élément-fichier ; le répertoire contient les photos réelles, et une restauration a besoin des deux, plus une image de base de données avec une extension vectorielle compatible. Faites d'abord l'export de la base puis la copie des fichiers, et testez la restauration sur une machine vierge au moins une fois : une sauvegarde non testée n'est pas une sauvegarde.

Comment importer mon dossier de photos existant ?

Montez le dossier en lecture seule dans le conteneur immich-server comme volume supplémentaire (par exemple - /srv/photos:/mnt/media/photos:ro), recréez le conteneur, puis dans Administration → External Libraries créez une bibliothèque et ajoutez le chemin du conteneur /mnt/media/photos. Immich indexe les fichiers sur place et ne les modifie ni ne les supprime jamais. L'erreur la plus courante est de saisir le chemin de l'hôte au lieu du chemin du conteneur, ce qui fait que le scan ne trouve rien.