Build Your Homelab: 39 – Installing Immich In Proxmox

Homelab 39 - Immich

One of the main things we set out to do while Building our own homelab, was to save costs. The other being taking control of our data and keeping it safe, but we need to somehow offset the costs of running a homelab. Yes, running a homelab is a lot cheaper than purchasing subscriptions for all our services, but there might be a fairly chunky initial start-up cost. Also never forget about the cost of electricity. Probably the most widely used service is a service that backs up the camera shots you take with your mobile phone. Something like Google Photos. And yes, Google Photos is amazing, but the costs can start to add up once you reach that initial 15Gb free storage. So let’s look at a self-hosted alternative called Immich. (Read the full article on Immich)


Step 1: Prepare the Install – New LXC

Unfortunately there is no helper script to install Immich as its own LXC container. The preferred method of installation at the date of publication is Docker Compose, but seeing as we want to make it as easy as possible, we will be using Docker Compose with Portainer. Note that you will need a fair bit of disk storage as the amount of photos on one’s phone can very quickly add up. We are going to be using a new Docker Instance, specifically created for Immich. This way, we still have a dedicated LXC for Immich, albeit running Docker. This also makes it easier to move just Immich should we run out of disk space on our main Docker node. However, feel free to add it to your existing Docker LXC or Docker VM.

For this, we can use helper-scripts.com and search for Docker. There should only be two results, and LXC or a VM. Just a quick note: If you want to use your GPU for processing some of the advanced AI features, you will need to set up GPU pass-though and this can only be done with a Docker VM. Although we are not going to look at getting that set up now, this is something to take into account for future use. We are going to use an LXC, the command for a Docker LXC is:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/docker.sh)"

Open up your Proxmox server and log in. In the left navigation window, expand Datacenter and select the Proxmox instance you want to install Immich in. In the middle navigation pane, click on Proxmox Shell Button to open the integrated console. Run the command above to start the installation. We are not going to go with the default options this time, so select Advanced settings when the SETTINGS window appears. We are going to go through the settings:

  • The first screen is just an informative screen informing you that you are about to create a new Docker LXC. Press enter on <Yes>
  • SETTINGS – Select the third option, Advanced Settings and press enter. We need to change the default settings this time round to include a MUCH bigger disk and change the container ID
  • TIP – The next screen will inform you that spacebar needs to be pressed to make a selection.
  • CONTAINER TYPE – There is no need for us to run a privileged container, so we are sticking to unprivileged.
  • PASSWORD – Now you need to set a root password. You can also leave it blank to automatically log in to the LXC container if you want.
  • PASSWORD VERIFICATION – If you entered a password in the previous step, re-enter it now and confirm both are the same.
  • CONTAINER ID – We can now select a container ID. Container ID’s normally go from 100 to 999, so select any ID you want. We are going to add our Docker LXC on ID 201 seeing as our “main” Docker LXC is on 200.
  • HOSTNAME – Select the hostname that this LXC container will identify itself with. The default is docker, but we already have a main docker, this is going to be our Immich Docker container, so we are changing it to immich.
  • DISK SIZE – Set the disk size in GB. This is one of the reasons we are in Advanced Mode. Yes, it is possible to resize an LXC disk after creation, but why not change it now. The default 4Gb is not even close to enough with most mobile phones now starting at 128Gb internal storage. We are starting with 100Gb, but can resize resources later if needed.
  • CORE COUNT – Immich minimum requirement is 2 cores, but 4 is recommended. Yes, it would be funny to go with 3 cores, but we are going to go with 4 as we are not going to add a GPU.
  • RAM – Immich specs state a minimum of 4GB, but recommends 6GB. We are adding 6 GB.
  • BRIDGE – The bridge is a network bridge for this LXC container. Leave as default and press enter.
  • IP ADDRESS – Here we can assign a static IP address for this container. It might be easier to assign a static IP if you don’t want to configure the IP on your router. If you want to rather leave the IP Address assigning to the Router, just leave as the default dhcp option and press enter.
  • APT-CACHER IP – This can be left as default (blank), just press enter.
  • IPV6 – The option to disable IPv6 is up to you. We are leaving it active, even though we are not running IPv6 (yet).
  • MTU SIZE – Just leave the default MTU size (blank) and press enter.
  • DNS SEARCH DOMAIN – If you want a default DNS search domain, you are welcome to add it here. Otherwise just leave it blank (which will take the settings of the host – ProxMox) and press enter.
  • DNS SERVER IP – Same as the previous, you can add a default IP for DNS queries, or just leave it blank to use the host’s settings.
  • MAC ADDRESS – You can set a static MAC address, or leave as blank to generate a new one.
  • VLAN – If you are unsure of this option, just leave it blank and press enter.
  • ADVANCED TAGS – You can edit the tags of this container. We are going to add the tag immich to our container and press enter.
  • SSH ACCESS – If you want to access the LXC via a shell running SSH (like you would with the integrated Console in ProxMox), select Yes and press enter.
  • SSH KEY – If you have an SSH key that you want to use for authentication, paste it here or leave blank if you want to use username and password authentication.
  • VERBOSE MODE – This will give a more detailed information as the services are busy installing. Either option is fine.
  • ADVANCED SETTINGS COMPLETE – If you are ready to create the Docker LXC, select yes and press enter.
  • STORAGE POOLS – You will be prompted to select a disk (if you have more than one). Select the disk where you want to add the storage and press enter.

The install will now run. You will be prompted if you want to Install Portainer, but we already have a Docker instance running Portainer, so we are going to say NO. If you select NO, you will also be prompted if you want to install the Portainer agent. Actually we do, because we want to use our running Portainer to also manage this Docker install, but we are going to select NO again (type N and press enter) so that we can install it manually the the next step.


Step 2: Install Portainer

If you already have another Docker environment running Portainer, access it and log in. In the left navigation menu, expand Environment-related and select Environments. Click the Portainer - Add Environment Button button. Select Docker Standalone and click Start Wizard. By default, the Agent should be selected but select it if not. You will be presented with the Docker command to get the Portainer agent installed.

docker run -d \
-p 9001:9001 \
--name portainer_agent \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
-v /:/host \
portainer/agent:2.27.3

Go back to Proxmox and select the newly installed Docker LXC, in our case called immich. Select the Proxmox Console Button to open an integrated console shell. If you sent a root password in the install, you will need to log in first with the username root and the password you selected. Paste the command and press enter. The install shoudl go fairly quick. Once completed, you can run the command to check that Portainer is running:

docker ps

If everything is running, back in the Portainer window, add the Name, which can be anything]. The environment address needs to be the address of the newly installed Immich LXC on port 9001, example: 192.168.1.36:9001. Click connect and you should be connected to this new Docker instance in your single Portainer WebUI.

Step 3: Install Immich

We know the pre-setup is quite a lot, but we are finally at a point where we can install the actual Immich. We are going to go with the official Portainer steps, which can be found here: https://immich.app/docs/install/portainer. However, we need to get the Docker Compose file from https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml:

#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
#   file: hwaccel.transcoding.yml
#   service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /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
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
#   file: hwaccel.ml.yml
#   service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm@sha256:42cba146593a5ea9a622002c1b7cba5da7be248650cbb64ecb9c6c33d29794b1
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: >-
pg_isready --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" || exit 1; Chksum="$$(psql --dbname="$${POSTGRES_DB}" --username="$${POSTGRES_USER}" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: >-
postgres -c shared_preload_libraries=vectors.so -c 'search_path="$$user", public, vectors' -c logging_collector=on -c max_wal_size=2GB -c shared_buffers=512MB -c wal_compression=on
restart: always
volumes:
model-cache:

In Portainer, from the dashboard, select the immich environment we just created. Go to Stacks in the left navigation pane, and click on Portainer Add Stack Button. Paste the entire contents of the docker-compose file into the Web Editor section. Change the values of the env_file sections from .env to stack.env in all sections.

Under the Environment Variables section, click on Advanced mode and add all the environment variables, as per the file: https://github.com/immich-app/immich/releases/latest/download/example.env

# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION=./library
# The location where your database files are stored. Network shares are not supported for the database
DB_DATA_LOCATION=./postgres
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
# TZ=Etc/UTC
# The Immich version to use. You can pin this to a specific version like "v1.71.0"
IMMICH_VERSION=release
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD=postgres
# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

Change the database password of you want. After tiving the stack a name, click on Portainer Deploy The Stack Button.

It might take a few minutes to install the stack due to the stack downloading all the relevant containers, but once done, you can access Immich on the Ip on port 2283, ex: http://192.168.1.36:2283


Conclusion

Although this install process was quite a bit longer and different to the norm, we have a dedicated LXC container (not VM) running our Immich service. This means we can scale the resources independent of our other Docker LXC and we can easily move Immich to a different Proxmox installation of we want, or just move to a different disk. This also means that backups is easier and separate from other services. We will look at the setup, reverse proxy and usage in our next instalment.