Post

Immich Server

Immich Server

Self-Host Your Photos

img-description docker

Immich is a open-source photo and video management solution, think Google Photos, but running on your own server. You get automatic mobile backup, AI-powered search, face recognition, and a slick interface, all without your data ever leaving your hands.

How to get it running

Before getting started, we need a place to install Immich and review the hardware specifications. Immich supports NVIDIA GPU acceleration, but it can also run entirely on a CPU if no GPU is available. In my case, I run Immich in Docker container without a graphics card, and it runs without issues. Check this guide on how_to_setup_docker

Requirements

  • docker - (min 6GB of RAM and 2 CPU cores)
  • (Nvidia gfx card) - optionel

Nvidia GFX card setup

If you intend to use a GPU for hardware acceleration, you should verify that your system can detect the graphics card. If your setup does not include a GPU, you can skip this step SSH in to the server

1
lspci

Immich supports NVIDIA GPUs with CUDA 5.2 or higher, which includes cards such as the GeForce GTX 950 and newer models.

The next step is configuring your GPU to be used inside the Docker container.

1
ubuntu-drivers devices

After installing the required drivers, your output should look similar to the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
dock@ImiichCT:/opt/pool/immich$ ubuntu-drivers devices
ERROR:root:aplay command not found
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00002204sv00001043sd000087B3bc03sc00i00
vendor   : NVIDIA Corporation
model    : GA102 [GeForce RTX 3090]
driver   : nvidia-driver-570 - distro non-free
driver   : nvidia-driver-580-server-open - distro non-free
driver   : nvidia-driver-535-server-open - distro non-free
driver   : nvidia-driver-570-server - distro non-free
driver   : nvidia-driver-570-open - distro non-free
driver   : nvidia-driver-535-server - distro non-free
driver   : nvidia-driver-580 - distro non-free
driver   : nvidia-driver-580-server - distro non-free
driver   : nvidia-driver-570-server-open - distro non-free
driver   : nvidia-driver-580-open - distro non-free recommended
driver   : xserver-xorg-video-nouveau - distro free builtin

Check for the distro’s non-free recommended driver. The current latest version is nvidia-driver-580-open. Install this version to ensure proper GPU support.

1
sudo ubuntu-drivers install -y nvidia-driver-580

Then reboot the server

1
sudo reboot

At this point, your GPU should be detected and running properly.

1
nvidia-smi

The output should look similar to the following. (Disclaimer: I don’t have an NVIDIA GPU in this container; this example is taken from a different container.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
hal@ai:~$ nvidia-smi
Sun Mar 15 07:57:25 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 590.48.01              Driver Version: 590.48.01      CUDA Version: 13.1     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3090        On  |   00000000:01:00.0 Off |                  N/A |
|  0%   52C    P8             40W /  350W |   12282MiB /  24576MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A          628698      C   python3                               12274MiB |
+-----------------------------------------------------------------------------------------+
hal@ai:~$

To enable GPU support in the container, the GPU must be installed on the host and made accessible to the Docker container.

So, we need to set up the production repository.

1
2
3
4
5
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

Then we need to update the packages

1
sudo apt-get update

Now it’s time to install the packages for the NVIDIA Container Toolkit.

1
2
3
4
5
6
export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.19.0-1
  sudo apt-get install -y \
      nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      nvidia-container-toolkit-base=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container-tools=${NVIDIA_CONTAINER_TOOLKIT_VERSION} \
      libnvidia-container1=${NVIDIA_CONTAINER_TOOLKIT_VERSION}

And setup docker to use the toolkit

1
sudo nvidia-ctk runtime configure --runtime=docker

Restart the docker

1
sudo systemctl restart docker

Then test if it works inside the container

1
docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

Now you should see (note this is from a diffrent container where i use my GPU)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
hal@ai:/opt/pool/ai-stack$ docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi
Mon Mar 16 08:03:57 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 590.48.01              Driver Version: 590.48.01      CUDA Version: 13.1     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3090        Off |   00000000:01:00.0 Off |                  N/A |
|  0%   40C    P8             13W /  350W |    1248MiB /  24576MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+
hal@ai:/opt/pool/ai-stack$

Immich setup

Check for docker

1
docker -v

And you should see something like this

1
2
dock@ImiichCT:/opt/immich$ docker -v
Docker version 29.3.0, build 5927d80

I use /opt/pool/immich as my path

1
sudo mkdir -p /opt/pool/immich

We need to change the folder ownership so we don’t have to type sudo every time.

1
sudo chown user:user -R /opt/pool

Next, navigate to the directory

1
cd /opt/pool/immich

Time to create the compose.yml file

1
nano compose.yml

Add the content below to your YML file. I won’t cover the YML syntax in depth, but there are a few important aspects to pay attention to.

  • /mnt/photos:/mnt/photos:ro

If you plan to use a network share, uncomment this line. The details of the network share will be discussed later, but it’s not required at this stage.

1
2
3
 extends: 
      file: hwaccel.ml.yml
      service: cuda

If your setup includes an NVIDIA graphics card, uncomment this line to enable GPU support.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
name: immich

services:
  immich-server:
    container_name: immich_photo_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    extends:
      file: hwaccel.transcoding.yml
      service: ${TRANSCODING_BACKEND:-cpu}
    volumes:
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
    #   - /mnt/photos:/mnt/photos:ro ## uncomment if you are using a network share
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env
    ports:
      - '2283:2283'
    depends_on:
      - redis
      - database
    restart: always
    healthcheck:
      disable: false

  immich-machine-learning:
    container_name: immich_machine_learning
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}-cuda
    #extends: - ## uncomment if you use a Nvidia GPU
      #file: hwaccel.ml.yml
      #service: cuda
    volumes:
      - model-cache:/cache 
    env_file:
      - .env
    restart: always
    healthcheck:
      disable: false

  redis:
    container_name: immich_redis
    image: docker.io/valkey/valkey:8-bookworm
    healthcheck:
      test: redis-cli ping || exit 1
    restart: always

  database:
    container_name: immich_postgres
    image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
      DB_STORAGE_TYPE: ${DB_STORAGE_TYPE:-SSD}
    volumes:
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
    env_file:
      - .env
    restart: always

volumes:
  model-cache:

After that, configure the .env file. The key aspect to focus on in this file is the

  • UPLOAD_LOCATION=./library
  • DB_DATA_LOCATION=./postgres
  • DB_PASSWORD=password
  • DB_USERNAME=user

UPLOAD_LOCATION=./library #This setting determines where your photo library will be stored. In my setup, I pointed it to my NAS to keep the container image small. Then, within the Immich admin panel, I mounted an external library linking all my photos from the NAS to Immich. In short: the container itself remains lightweight, while all your photos are stored externally on the NAS and fully accessible in Immich.

  • UPLOAD_LOCATION=./mnt/immich (Instructions for setting this up are provided later in the guide.)
  • Inside Immich i added a External Library ( we do this when Immich is up and running in the admin panel)
1
nano .env

Paste the content below into the file, and make sure to update the settings mentioned above.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Required paths
UPLOAD_LOCATION=./library
DB_DATA_LOCATION=./postgres

# Optional timezone (not needed if localtime is mounted)
# TZ=Etc/UTC

# Version control
IMMICH_VERSION=release

# Postgres authentication
DB_PASSWORD=password
DB_USERNAME=user
DB_DATABASE_NAME=immich

# Optional tuning
DB_STORAGE_TYPE=SSD ## Change to HDD if you have a spinning harddisk 

# transcoding
TRANSCODING_BACKEND=nvenc

Now we need to make the hwaccel.ml.yml file If u use a Nvidia GFX card do this if not skip

1
nano hwaccel.ml.yml

Paste this in it

1
2
3
4
5
6
7
8
9
10
services:
  cuda:
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities:
                - gpu

Now for transcoding

1
nano hwaccel.transcoding.yml

Paste this in it if you use a Nvidia GFX card if not skip

1
2
3
4
5
6
7
8
9
10
11
12
services:
  nvenc:
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities:
                - gpu
                - compute
                - video

SMB Share

To use an SMB network share with Immich, I have a folder called photo on my OpenMediaVault server, which is shared over SMB. This guide won’t cover the SMB setup itself, but I plan to create a dedicated guide for that in the near future.

make a dir for the credentials

1
sudo mkdir -p /etc/smb-credentials

create credentials file

1
sudo nano /etc/smb-credentials/photos

Make sure to replace the credentials in the configuration with the username and password that have access to your network share.

1
2
username=user
password=password

Adjust the file permissions as needed. In my case, I set them to root with mode 600, meaning only root has read and write access.

1
2
sudo chmod 600 /etc/smb-credentials/photos
sudo chown root:root /etc/smb-credentials/photos

Verify that the file permissions have been applied properly and are functioning as intended.

1
 ls -l /etc/smb-credentials/photos

Update fstab to mount the share

1
sudo nano /etc/fstab

Make/paste the mount path in botton of the file (correct the ip/share to your need)

1
//10.10.10.8/photos /mnt/photos cifs credentials=/etc/smb-credentials/photos,iocharset=utf8,vers=3.0,ro,nofail 0 0

For this to work we need cifs-utils installed so we need some additional packages

1
sudo apt update && sudo apt install cifs-utils

Now reboot

1
sudo reboot

First start

Now we can start the server and see the results of all the setup work we’ve done.

1
2
cd /opt/pool/immich
docker compose up -d

Check it with

1
docker ps

Connect to the server

  • http://10.10.10.8:2283

Enjoy …

Immich Github
Immich Backup & Retore
Nvidia CUDA GPU
NVIDIA Container Toolkit

This post is licensed under CC BY 4.0 by the author.