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 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 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 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 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 . 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 .
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.