readytouse

This commit is contained in:
Rypeur33 2026-06-05 14:53:29 +02:00
parent 91063c1a0c
commit 9281354f2e
16 changed files with 690 additions and 0 deletions

3
immich-ansible/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.retry
.vault_pass
.env

137
immich-ansible/README.md Normal file
View file

@ -0,0 +1,137 @@
# Immich Ansible
Playbook Ansible pour installer Immich auto-hébergé avec Docker Compose, PostgreSQL, Redis/Valkey, machine-learning et Nginx/Certbot.
Il reprend le modèle du projet Forgejo fourni :
- même host Ansible ;
- installation Docker Compose v2 ;
- reverse proxy Nginx + certificat Let's Encrypt ;
- port Docker hôte non standard ;
- données applicatives persistantes bind-mountées sur le partage NFS.
## Structure
```text
immich-ansible/
├── ansible.cfg
├── inventory.ini
├── playbook.yml
├── group_vars/
│ └── immich.yml
├── templates/
│ ├── .env.j2
│ └── docker-compose.yml.j2
└── roles/
└── nginx/
```
## Configuration appliquée
```yaml
immich_domain: "immich.esfs.fr"
immich_dir: "/opt/immich"
nfs_mount_point: "/mnt/nfs-share"
immich_library_path: "/mnt/nfs-share/applications/immich/library"
immich_postgres_data_path: "/opt/immich/postgres"
immich_host_http_port: "32283"
immich_container_http_port: "2283"
```
Nginx proxy vers :
```text
http://127.0.0.1:32283
```
L'accès final sera :
```text
https://immich.esfs.fr
```
## Point important sur NFS
La bibliothèque Immich est sur NFS :
```text
/mnt/nfs-share/applications/immich/library
```
PostgreSQL est volontairement local :
```text
/opt/immich/postgres
```
C'est fait ainsi parce que le fichier `example.env` officiel Immich précise que les partages réseau ne sont pas supportés pour `DB_DATA_LOCATION`. C'est aussi cohérent avec le projet Forgejo fourni, où les données Forgejo sont sur NFS mais PostgreSQL reste local.
## Lancement
Depuis le dossier du projet :
```bash
ansible-playbook playbook.yml
```
Ou explicitement :
```bash
ansible-playbook -i inventory.ini playbook.yml
```
## Après installation
Ouvre :
```text
https://immich.esfs.fr
```
Puis crée le premier compte administrateur via l'assistant Immich.
## Variables utiles
Dans `group_vars/immich.yml` :
```yaml
immich_db_password: "Yb8qD7vRc4Nz29AhKp6Lx5Tf"
immich_version: "v2"
immich_host_http_port: "32283"
immich_nginx_client_max_body_size: "10G"
```
Le mot de passe PostgreSQL est volontairement alphanumérique uniquement.
## Mise à jour Immich
Sur le serveur :
```bash
cd /opt/immich
docker compose pull
docker compose up -d
```
Ou relancer le playbook Ansible.
## Sauvegarde
À sauvegarder régulièrement :
```text
/mnt/nfs-share/applications/immich/library
/opt/immich/postgres
/opt/immich/docker-compose.yml
/opt/immich/.env
```
Pour une sauvegarde froide :
```bash
cd /opt/immich
docker compose down
# sauvegarde
docker compose up -d
```

View file

@ -0,0 +1,10 @@
[defaults]
inventory = inventory.ini
host_key_checking = False
retry_files_enabled = False
stdout_callback = default
interpreter_python = auto_silent
[privilege_escalation]
become = True
become_method = sudo

View file

@ -0,0 +1,55 @@
---
# Immich variables (group_vars/immich.yml)
# Reprise du modèle Forgejo fourni : Docker Compose, Nginx/Certbot, host identique,
# données applicatives persistantes sur NFS, base PostgreSQL locale.
# Réseau / domaine public
nginx_required: true
immich_domain: "immich.esfs.fr"
letsencrypt_email: "admin@esfs.fr"
immich_nginx_site_filename: "immich.esfs.fr.conf"
immich_nginx_client_max_body_size: "10G"
# Chemins d'installation
immich_dir: "/opt/immich"
nfs_mount_point: "/mnt/nfs-share"
check_nfs_mount: true
# Données persistantes
# La bibliothèque Immich contient les uploads, thumbnails, encoded-video, profile, backups, etc.
# Elle est bind-mountée sur le partage NFS, comme les données Forgejo dans le projet d'exemple.
immich_library_path: "{{ nfs_mount_point }}/applications/immich/library"
# Important : Immich déconseille / ne supporte pas DB_DATA_LOCATION sur un partage réseau.
# On garde donc PostgreSQL en local, comme PostgreSQL Forgejo était local dans le projet fourni.
immich_postgres_data_path: "{{ immich_dir }}/postgres"
immich_model_cache_path: "{{ immich_dir }}/model-cache"
# Ports exposés Docker
# Nginx proxy vers 127.0.0.1:{{ immich_host_http_port }}.
# Port hôte volontairement non standard pour éviter les conflits avec les autres applis web.
immich_host_http_port: "32283"
immich_container_http_port: "2283"
# Images / version Immich
# v2 suit la branche majeure stable actuelle. Remplacer par une version précise si besoin, ex: v2.1.0.
immich_version: "v2"
immich_server_image: "ghcr.io/immich-app/immich-server"
immich_machine_learning_image: "ghcr.io/immich-app/immich-machine-learning"
immich_redis_image: "docker.io/valkey/valkey:9"
immich_postgres_image: "ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0"
# PostgreSQL Immich
immich_db_username: "postgres"
immich_db_database: "immich"
# Alphanumérique uniquement, comme recommandé par Immich.
immich_db_password: "Yb8qD7vRc4Nz29AhKp6Lx5Tf"
# Système
server_timezone: "Europe/Paris"
docker_remove_conflicting_packages: true
# Permissions
immich_library_mode: "0777"
immich_postgres_uid: "999"
immich_postgres_gid: "999"

View file

@ -0,0 +1,2 @@
[immich]
forgejo-server ansible_host=92.222.203.70 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/ovhkey

210
immich-ansible/playbook.yml Normal file
View file

@ -0,0 +1,210 @@
---
- name: Installer Immich avec Docker Compose
hosts: immich
become: true
tasks:
- name: Installer les prérequis système
ansible.builtin.apt:
name:
- ca-certificates
- curl
- gnupg
- lsb-release
- nfs-common
state: present
update_cache: true
- name: Vérifier que le partage NFS est monté
ansible.builtin.command:
cmd: findmnt -T "{{ nfs_mount_point }}"
register: nfs_mount_check
changed_when: false
failed_when: nfs_mount_check.rc != 0
when: check_nfs_mount | bool
- name: Définir l'architecture Docker APT
ansible.builtin.set_fact:
docker_apt_arch: >-
{{
{
'x86_64': 'amd64',
'aarch64': 'arm64',
'armv7l': 'armhf',
'armv6l': 'armhf'
}.get(ansible_architecture, ansible_architecture)
}}
docker_apt_distribution: >-
{{
'ubuntu' if ansible_distribution == 'Ubuntu'
else 'debian' if ansible_distribution == 'Debian'
else ansible_distribution | lower
}}
- name: Supprimer les anciens paquets Docker conflictuels
ansible.builtin.apt:
name:
- docker.io
- docker-doc
- docker-compose
- podman-docker
- containerd
- runc
state: absent
when: docker_remove_conflicting_packages | bool
- name: Créer le dossier des clés APT
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
owner: root
group: root
mode: "0755"
- name: Installer la clé GPG du dépôt Docker officiel
ansible.builtin.get_url:
url: "https://download.docker.com/linux/{{ docker_apt_distribution }}/gpg"
dest: /etc/apt/keyrings/docker.asc
owner: root
group: root
mode: "0644"
- name: Ajouter le dépôt Docker officiel
ansible.builtin.apt_repository:
repo: "deb [arch={{ docker_apt_arch }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/{{ docker_apt_distribution }} {{ ansible_distribution_release }} stable"
filename: docker
state: present
update_cache: true
- name: Installer Docker Engine et Docker Compose v2
ansible.builtin.apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: present
update_cache: true
- name: Activer et démarrer Docker
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Créer le dossier Immich
ansible.builtin.file:
path: "{{ immich_dir }}"
state: directory
owner: root
group: root
mode: "0755"
- name: Créer la bibliothèque Immich sur le NFS
ansible.builtin.file:
path: "{{ immich_library_path }}"
state: directory
mode: "{{ immich_library_mode }}"
recurse: true
- name: Forcer les permissions sur la bibliothèque Immich NFS
ansible.builtin.command:
cmd: chmod -R {{ immich_library_mode }} "{{ immich_library_path }}"
changed_when: false
- name: Créer le dossier PostgreSQL local Immich
ansible.builtin.file:
path: "{{ immich_postgres_data_path }}"
state: directory
owner: "{{ immich_postgres_uid }}"
group: "{{ immich_postgres_gid }}"
mode: "0700"
- name: Créer le dossier de cache machine-learning Immich
ansible.builtin.file:
path: "{{ immich_model_cache_path }}"
state: directory
owner: root
group: root
mode: "0777"
- name: Déployer le fichier .env Immich
ansible.builtin.template:
src: templates/.env.j2
dest: "{{ immich_dir }}/.env"
owner: root
group: root
mode: "0600"
notify: Redémarrer Immich
- name: Déployer docker-compose.yml Immich
ansible.builtin.template:
src: templates/docker-compose.yml.j2
dest: "{{ immich_dir }}/docker-compose.yml"
owner: root
group: root
mode: "0644"
notify: Redémarrer Immich
- name: Supprimer les anciens conteneurs Immich portant les mêmes noms
ansible.builtin.shell: |
old_ids=$(docker ps -aq \
--filter "name=immich_server" \
--filter "name=immich_machine_learning" \
--filter "name=immich_redis" \
--filter "name=immich_postgres")
if [ -n "$old_ids" ]; then
docker rm -f $old_ids
fi
printf "%s" "$old_ids"
changed_when: removed_immich_containers.stdout != ''
register: removed_immich_containers
- name: Démarrer Immich
ansible.builtin.command:
cmd: docker compose up -d
chdir: "{{ immich_dir }}"
register: immich_compose_up
changed_when: >-
'Started' in immich_compose_up.stdout or
'Created' in immich_compose_up.stdout or
'Recreated' in immich_compose_up.stdout or
'Running' in immich_compose_up.stdout
- name: Attendre que le port HTTP Immich soit ouvert localement
ansible.builtin.wait_for:
host: 127.0.0.1
port: "{{ immich_host_http_port }}"
delay: 5
timeout: 240
state: started
- name: Attendre que le conteneur Immich Server soit en état running
ansible.builtin.shell: |
cid=$(docker compose ps -q immich-server)
if [ -z "$cid" ]; then
exit 1
fi
status=$(docker inspect "$cid" | grep -m1 '"Status":' | awk -F'"' '{print $4}')
[ "$status" = "running" ]
args:
chdir: "{{ immich_dir }}"
register: immich_container_status
retries: 30
delay: 5
until: immich_container_status.rc == 0
changed_when: false
- name: Lancer le rôle Nginx configuration réseau
ansible.builtin.include_role:
name: nginx
when: nginx_required | bool
handlers:
- name: Redémarrer Immich
ansible.builtin.command:
cmd: docker compose up -d
chdir: "{{ immich_dir }}"
register: immich_restart
changed_when: true

View file

@ -0,0 +1,20 @@
# Rôle Nginx Immich
Ce rôle configure Nginx comme reverse proxy HTTPS pour Immich.
Variables obligatoires :
```yaml
immich_domain: "immich.esfs.fr"
immich_host_http_port: "32283"
letsencrypt_email: "admin@esfs.fr"
```
Variable optionnelle :
```yaml
immich_nginx_client_max_body_size: "10G"
immich_nginx_site_filename: "immich.esfs.fr.conf"
```
Le rôle obtient automatiquement un certificat Let's Encrypt avec `certbot --nginx`.

View file

@ -0,0 +1,7 @@
---
# Nom du fichier dans /etc/nginx/sites-available et sites-enabled.
# Par défaut : "{{ immich_domain }}.conf"
# immich_nginx_site_filename: "{{ immich_domain }}.conf"
# Uploads photos/vidéos : taille élevée par défaut.
immich_nginx_client_max_body_size: "10G"

View file

@ -0,0 +1,10 @@
---
- name: reload nginx
ansible.builtin.command: nginx -t
changed_when: true
notify: do reload nginx
- name: do reload nginx
ansible.builtin.service:
name: nginx
state: reloaded

View file

@ -0,0 +1,63 @@
---
- name: Vérifier les variables obligatoires du rôle Nginx Immich
ansible.builtin.assert:
that:
- immich_domain is defined
- immich_domain | length > 0
- immich_host_http_port is defined
- immich_host_http_port | string | length > 0
- letsencrypt_email is defined
- letsencrypt_email | length > 0
fail_msg: >-
Variables obligatoires manquantes pour le rôle nginx :
immich_domain, immich_host_http_port, letsencrypt_email.
- name: Définir le nom du fichier de site Nginx Immich
ansible.builtin.set_fact:
immich_nginx_site_filename_resolved: "{{ immich_nginx_site_filename | default(immich_domain ~ '.conf') }}"
- name: Supprimer le site Nginx par défaut si présent
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: reload nginx
- name: Déployer la configuration HTTP temporaire Immich
ansible.builtin.template:
src: immich.http-only.conf.j2
dest: "/etc/nginx/sites-available/{{ immich_nginx_site_filename_resolved }}"
owner: root
group: root
mode: "0644"
notify: reload nginx
- name: Activer le site Nginx Immich
ansible.builtin.file:
src: "/etc/nginx/sites-available/{{ immich_nginx_site_filename_resolved }}"
dest: "/etc/nginx/sites-enabled/{{ immich_nginx_site_filename_resolved }}"
state: link
force: true
notify: reload nginx
- name: Appliquer la configuration HTTP temporaire
ansible.builtin.meta: flush_handlers
- name: Obtenir le certificat Let's Encrypt pour Immich
ansible.builtin.command: >-
certbot certonly --non-interactive --agree-tos
--email {{ letsencrypt_email }}
--nginx -d {{ immich_domain }}
args:
creates: "/etc/letsencrypt/live/{{ immich_domain }}/fullchain.pem"
- name: Déployer la configuration HTTPS finale Immich
ansible.builtin.template:
src: immich.https.conf.j2
dest: "/etc/nginx/sites-available/{{ immich_nginx_site_filename_resolved }}"
owner: root
group: root
mode: "0644"
notify: reload nginx
- name: Appliquer la configuration HTTPS finale
ansible.builtin.meta: flush_handlers

View file

@ -0,0 +1,15 @@
---
- name: Installer Nginx et Certbot
ansible.builtin.apt:
update_cache: true
name:
- nginx
- certbot
- python3-certbot-nginx
state: present
- name: Activer et démarrer Nginx
ansible.builtin.service:
name: nginx
state: started
enabled: true

View file

@ -0,0 +1,14 @@
---
- name: Installer / mettre à jour Nginx et Certbot
ansible.builtin.include_tasks:
file: install.yml
apply:
tags: [nginx_update, nginx_config]
tags: [nginx_update, nginx_config]
- name: Configurer Nginx pour Immich
ansible.builtin.include_tasks:
file: config.yml
apply:
tags: [nginx_config]
tags: [nginx_config]

View file

@ -0,0 +1,25 @@
# Configuration HTTP temporaire pour obtenir le certificat Let's Encrypt
server {
listen 80;
server_name {{ immich_domain }};
client_max_body_size {{ immich_nginx_client_max_body_size | default('10G') }};
location / {
proxy_pass http://127.0.0.1:{{ immich_host_http_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_request_buffering off;
proxy_buffering off;
}
}

View file

@ -0,0 +1,41 @@
# HTTP -> HTTPS
server {
listen 80;
server_name {{ immich_domain }};
return 301 https://$host$request_uri;
}
# Immich HTTPS reverse proxy
server {
listen 443 ssl http2;
server_name {{ immich_domain }};
client_max_body_size {{ immich_nginx_client_max_body_size | default('10G') }};
ssl_certificate /etc/letsencrypt/live/{{ immich_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ immich_domain }}/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
location / {
proxy_pass http://127.0.0.1:{{ immich_host_http_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_request_buffering off;
proxy_buffering off;
}
}

View file

@ -0,0 +1,14 @@
# Fichier généré par Ansible - ne pas modifier directement.
# Bibliothèque Immich : bind mount vers le partage NFS
UPLOAD_LOCATION={{ immich_library_path }}
# Base PostgreSQL : volontairement locale, pas sur NFS
DB_DATA_LOCATION={{ immich_postgres_data_path }}
TZ={{ server_timezone }}
IMMICH_VERSION={{ immich_version }}
DB_PASSWORD={{ immich_db_password }}
DB_USERNAME={{ immich_db_username }}
DB_DATABASE_NAME={{ immich_db_database }}

View file

@ -0,0 +1,64 @@
name: immich
services:
immich-server:
image: "{{ immich_server_image }}:${IMMICH_VERSION:-{{ immich_version }}}"
container_name: immich_server
restart: always
depends_on:
- redis
- database
env_file:
- .env
volumes:
- "${UPLOAD_LOCATION}:/data"
- /etc/localtime:/etc/localtime:ro
ports:
- "127.0.0.1:{{ immich_host_http_port }}:{{ immich_container_http_port }}"
healthcheck:
disable: false
networks:
- immich
immich-machine-learning:
image: "{{ immich_machine_learning_image }}:${IMMICH_VERSION:-{{ immich_version }}}"
container_name: immich_machine_learning
restart: always
env_file:
- .env
volumes:
- "{{ immich_model_cache_path }}:/cache"
healthcheck:
disable: false
networks:
- immich
redis:
image: "{{ immich_redis_image }}"
container_name: immich_redis
restart: always
healthcheck:
test: redis-cli ping || exit 1
networks:
- immich
database:
image: "{{ immich_postgres_image }}"
container_name: immich_postgres
restart: always
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: "--data-checksums"
volumes:
- "${DB_DATA_LOCATION}:/var/lib/postgresql/data"
shm_size: 128mb
healthcheck:
disable: false
networks:
- immich
networks:
immich:
name: immich