2025-06-01 10:50:08 +02:00
#!/usr/bin/env bash
2026-08-25 11:04:15 +02:00
_cs_boot = " ${ COMMUNITY_SCRIPTS_CORE_DIR :-$( dirname " ${ BASH_SOURCE [0] } " ) /../../core } /core/build.func"
source " $_cs_boot " 2>/dev/null || source <( curl -fsSL " ${ COMMUNITY_SCRIPTS_CORE_URL :- https ://raw.githubusercontent.com/community-scripts/core/main } /core/build.func" )
2026-01-06 13:28:12 +01:00
# Copyright (c) 2021-2026 community-scripts ORG
2025-06-01 10:50:08 +02:00
# Author: vhsdream
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
2026-02-24 15:11:53 +01:00
# Source: https://immich.app | Github: https://github.com/immich-app/immich
2025-06-01 10:50:08 +02:00
APP = "immich"
var_tags = " ${ var_tags :- photos } "
var_disk = " ${ var_disk :- 20 } "
var_cpu = " ${ var_cpu :- 4 } "
2026-01-22 07:41:58 -05:00
var_ram = " ${ var_ram :- 6144 } "
2025-06-01 10:50:08 +02:00
var_os = " ${ var_os :- debian } "
2025-09-18 15:15:54 -04:00
var_version = " ${ var_version :- 13 } "
2026-06-21 02:56:49 +10:00
var_arm64 = " ${ var_arm64 :- yes } "
2025-06-01 10:50:08 +02:00
var_unprivileged = " ${ var_unprivileged :- 1 } "
2025-12-08 13:52:30 +01:00
var_gpu = " ${ var_gpu :- yes } "
2025-06-01 10:50:08 +02:00
header_info " $APP "
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/immich ]] ; then
msg_error "No ${ APP } Installation Found!"
exit
fi
2025-09-18 15:15:54 -04:00
if [[ -f /etc/apt/sources.list.d/immich.list ]] ; then
msg_error "Wrong Debian version detected!"
msg_error "You must upgrade your LXC to Debian Trixie before updating."
msg_error "Please visit https://github.com/community-scripts/ProxmoxVE/discussions/7726 for details."
echo " ${ TAB3 } If you have upgraded your LXC to Trixie and you still see this message, please open an Issue in the Community-Scripts repo."
exit
fi
2025-06-19 01:55:39 -04:00
2026-03-07 15:44:33 +01:00
if ! grep -qE '(^|[[:space:]])testing([[:space:]]|$)' /etc/apt/sources.list.d/debian.sources 2>/dev/null; then
2025-10-12 14:50:48 -04:00
msg_info "Adding Debian Testing repo"
2026-03-07 15:44:33 +01:00
if grep -q "trixie-updates" /etc/apt/sources.list.d/debian.sources 2>/dev/null; then
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
else
sed -i '/^[[:space:]]*Suites:.*trixie/ s/$/ testing/' /etc/apt/sources.list.d/debian.sources
fi
2025-10-12 14:50:48 -04:00
cat <<EOF >/etc/apt/preferences.d/preferences
Package: *
Pin: release a=unstable
Pin-Priority: 450
Package: *
Pin:release a=testing
Pin-Priority: 450
EOF
2026-01-31 20:07:27 -05:00
[[ -f /etc/apt/preferences.d/immich ]] && rm /etc/apt/preferences.d/immich
2026-09-24 08:06:49 +02:00
apt_update_safe
2025-10-12 14:50:48 -04:00
msg_ok "Added Debian Testing repo"
2026-01-14 11:10:58 -05:00
fi
if ! dpkg -l "libmimalloc3" | grep -q '3.1' || ! dpkg -l "libde265-dev" | grep -q '1.0.16' ; then
msg_info "Installing/upgrading Testing repo packages"
$STD apt install -t testing libmimalloc3 libde265-dev -y
msg_ok "Installed/upgraded Testing repo packages"
2025-09-18 15:15:54 -04:00
fi
2025-11-20 12:08:25 -05:00
if [[ ! -f /etc/apt/sources.list.d/mise.list ]] ; then
msg_info "Installing Mise"
curl -fSs https://mise.jdx.dev/gpg-key.pub | tee /etc/apt/keyrings/mise-archive-keyring.pub 1>/dev/null
2026-06-22 23:35:14 +10:00
echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.pub arch= $( arch_resolve) ] https://mise.jdx.dev/deb stable main" >/etc/apt/sources.list.d/mise.list
2026-02-02 13:01:17 +01:00
ensure_dependencies mise
2025-11-20 12:08:25 -05:00
msg_ok "Installed Mise"
fi
2025-06-01 10:50:08 +02:00
STAGING_DIR = /opt/staging
BASE_DIR = ${ STAGING_DIR } /base-images
SOURCE_DIR = ${ STAGING_DIR } /image-source
2025-12-18 11:53:41 -05:00
cd /tmp
2026-10-04 14:03:24 +02:00
RELEASE = "v3.2.4"
2025-06-01 10:50:08 +02:00
if [[ -f ~/.intel_version ]] ; then
2026-10-04 14:03:24 +02:00
INTEL_SRC = "https://raw.githubusercontent.com/immich-app/immich/ ${ RELEASE } /machine-learning"
curl -fsSL " ${ INTEL_SRC } /scripts/install-intel-runtime.sh" -o ./intel-runtime 2>/dev/null ||
curl_with_retry " ${ INTEL_SRC } /Dockerfile" "./intel-runtime"
readarray -t INTEL_URLS < <( grep -oE 'https://github\.com/intel/[^[:space:]]+\.deb' ./intel-runtime)
INTEL_RELEASE = " $( grep -oE 'intel-opencl-icd_[^_]+' ./intel-runtime | cut -d_ -f2) " || true
rm -f ./intel-runtime
if [[ -z " $INTEL_RELEASE " ]] ; then
msg_warn "No Intel runtime found for Immich ${ RELEASE } , keeping the installed one"
elif [[ " $INTEL_RELEASE " != " $( cat ~/.intel_version) " ]] ; then
2026-03-20 09:14:24 -04:00
msg_info "Updating Intel OpenVINO dependencies"
2025-06-01 10:50:08 +02:00
for url in " ${ INTEL_URLS [@] } " ; do
2026-03-16 20:23:46 +01:00
curl_with_retry " $url " " $( basename " $url " ) "
2025-06-01 10:50:08 +02:00
done
2025-09-18 15:15:54 -04:00
$STD apt-mark unhold libigdgmm12
2026-02-02 08:41:06 -05:00
$STD apt install -y --allow-downgrades ./libigdgmm12*.deb
2025-12-18 11:53:41 -05:00
rm ./libigdgmm12*.deb
2025-06-19 01:55:39 -04:00
$STD apt install -y ./*.deb
2025-06-01 10:50:08 +02:00
rm ./*.deb
2025-09-18 15:15:54 -04:00
$STD apt-mark hold libigdgmm12
2026-01-16 09:32:13 +01:00
dpkg-query -W -f= '${Version}\n' intel-opencl-icd >~/.intel_version
2026-03-20 09:14:24 -04:00
msg_ok "Updated Intel OpenVINO dependencies"
2025-06-01 10:50:08 +02:00
fi
fi
if [[ -f ~/.immich_library_revisions ]] ; then
2026-08-21 07:55:32 +02:00
libraries =( "libjxl" "jpegli" "libheif" "libraw" "imagemagick" "libvips" )
2025-07-11 02:35:45 -04:00
cd " $BASE_DIR "
2026-02-26 02:45:59 -05:00
msg_warn "Checking for updates to custom image-processing libraries (recompile time: 2-15min per library)"
2026-09-23 16:13:54 +02:00
ensure_dependencies liblcms2-dev libjpeg62-turbo-dev libspng-dev libexif-dev
2025-07-11 02:35:45 -04:00
$STD git pull
for library in " ${ libraries [@] } " ; do
compile_" $library "
done
2025-08-18 10:26:27 -04:00
msg_ok "Image-processing libraries up to date"
2025-06-01 10:50:08 +02:00
fi
2025-10-15 16:20:56 -04:00
2026-03-19 22:18:27 +01:00
if check_for_gh_release "Immich" "immich-app/immich" " ${ RELEASE } " "each release is tested individually before the version is updated. Please do not open issues for this" ; then
2026-01-29 14:35:00 -05:00
if [[ $( cat ~/.immich) > "2.5.1" ]] ; then
msg_info "Enabling Maintenance Mode"
cd /opt/immich/app/bin
2026-08-31 08:50:44 +02:00
$STD ./immich-admin enable-maintenance-mode || true
2026-01-29 14:35:00 -05:00
export MAINT_MODE = 1
$STD cd -
msg_ok "Enabled Maintenance Mode"
fi
2025-08-29 12:27:24 +02:00
msg_info "Stopping Services"
systemctl stop immich-web
systemctl stop immich-ml
2025-10-15 16:20:56 -04:00
msg_ok "Stopped Services"
2026-07-12 11:48:43 -04:00
VCHORD_RELEASE = "1.1.1"
2026-07-13 12:59:52 +03:00
PG_VERSION = $( ls /etc/postgresql/ 2>/dev/null | sort -V | tail -1)
PG_VERSION = ${ PG_VERSION :- 16 }
2026-01-31 20:07:27 -05:00
[[ -f ~/.vchord_version ]] && mv ~/.vchord_version ~/.vectorchord
2026-03-19 22:18:27 +01:00
if check_for_gh_release "VectorChord" "tensorchord/VectorChord" " ${ VCHORD_RELEASE } " "updated together with Immich after testing" ; then
2026-07-05 16:03:56 -04:00
# dead tuples in smart_search/face_search make the REINDEX below fail with
# "missing chunk ... for toast value" on VectorChord 1.0.0 (#15588); must vacuum
# while still on the old extension version, a post-upgrade vacuum errors instead
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) smart_search;"
$STD sudo -u postgres psql -d immich -c "VACUUM (ANALYZE) face_search;"
2026-07-13 12:59:52 +03:00
fetch_and_deploy_gh_release "VectorChord" "tensorchord/VectorChord" "binary" " ${ VCHORD_RELEASE } " "/tmp" "postgresql- ${ PG_VERSION } -vchord_*_ $( arch_resolve) .deb"
2025-08-29 12:27:24 +02:00
systemctl restart postgresql
2025-10-15 16:20:56 -04:00
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vector UPDATE;"
$STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vchord UPDATE;"
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX face_index;"
$STD sudo -u postgres psql -d immich -c "REINDEX INDEX clip_index;"
2025-06-19 01:55:39 -04:00
fi
2026-03-16 17:32:16 +01:00
ensure_dependencies ccache gcc-13 g++-13
2025-06-01 10:50:08 +02:00
2025-10-15 16:20:56 -04:00
INSTALL_DIR = "/opt/ ${ APP } "
UPLOAD_DIR = " $( sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env) "
SRC_DIR = " ${ INSTALL_DIR } /source"
APP_DIR = " ${ INSTALL_DIR } /app"
2026-07-03 19:30:41 +02:00
PLUGIN_DIR = " ${ APP_DIR } /plugins/immich-plugin-core"
2025-10-15 16:20:56 -04:00
ML_DIR = " ${ APP_DIR } /machine-learning"
GEO_DIR = " ${ INSTALL_DIR } /geodata"
2026-01-31 20:07:27 -05:00
[[ -f " $ML_DIR " /ml_start.sh ]] && cp " $ML_DIR " /ml_start.sh " $INSTALL_DIR "
2026-02-06 14:57:43 -05:00
if grep -qs "set -a" " $APP_DIR " /bin/start.sh && grep -qs "warnings" " $APP_DIR " /bin/start.sh; then
2025-08-29 12:27:24 +02:00
cp " $APP_DIR " /bin/start.sh " $INSTALL_DIR "
else
cat <<EOF >"$INSTALL_DIR"/start.sh
2025-08-01 15:06:03 -04:00
#!/usr/bin/env bash
set -a
2025-08-20 15:47:44 -04:00
. ${INSTALL_DIR}/.env
2025-08-01 15:06:03 -04:00
set +a
2026-02-06 14:57:43 -05:00
/usr/bin/node --no-warnings ${APP_DIR}/dist/main.js "\$@"
2025-08-01 15:06:03 -04:00
EOF
2025-08-29 12:27:24 +02:00
chmod +x " $INSTALL_DIR " /start.sh
fi
2025-08-23 01:43:16 -04:00
2025-08-29 12:27:24 +02:00
(
shopt -s dotglob
rm -rf " ${ APP_DIR :? } " /*
)
2025-08-23 01:43:16 -04:00
2026-02-04 08:48:18 -05:00
setup_uv
2026-03-15 20:08:15 +01:00
CLEAN_INSTALL = 1 fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" " ${ RELEASE } " " $SRC_DIR "
2026-03-16 20:36:21 +01:00
PNPM_VERSION = " $( jq -r '.packageManager | split("@")[1] | split("+")[0]' ${ SRC_DIR } /package.json) "
2025-08-29 12:27:24 +02:00
export COREPACK_ENABLE_DOWNLOAD_PROMPT = 0
export CI = 1
2026-07-03 19:30:41 +02:00
NODE_VERSION = "24" NODE_MODULE = "corepack" setup_nodejs
$STD corepack prepare "pnpm@ ${ PNPM_VERSION } " --activate
export PATH = "/root/.local/share/pnpm/bin: $PATH "
$STD pnpm config set --global dangerouslyAllowAllBuilds true
2025-08-29 12:27:24 +02:00
2026-07-03 19:30:41 +02:00
msg_info "Updating Immich web and microservices"
cd " $SRC_DIR " /server
2025-08-29 12:27:24 +02:00
# server build
2026-07-03 19:30:41 +02:00
$STD pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build
$STD pnpm --filter immich --prod --no-optional deploy " $APP_DIR "
2026-09-10 16:23:08 -04:00
export SHARP_FORCE_GLOBAL_LIBVIPS = true
$STD pnpm --dir " $APP_DIR /node_modules/sharp" exec npm run build
2026-04-08 19:47:10 +02:00
# Patch helmet.json: disable upgrade-insecure-requests for HTTP access
if [[ -f " $APP_DIR /helmet.json" ]] ; then
jq '.contentSecurityPolicy.directives["upgrade-insecure-requests"] = null' " $APP_DIR /helmet.json" >" $APP_DIR /helmet.json.tmp" && mv " $APP_DIR /helmet.json.tmp" " $APP_DIR /helmet.json"
fi
2025-08-29 12:27:24 +02:00
cp " $APP_DIR " /package.json " $APP_DIR " /bin
2026-01-31 20:07:27 -05:00
sed -i "s|^start| ${ APP_DIR } /bin/start|" " $APP_DIR " /bin/immich-admin
2025-08-29 12:27:24 +02:00
2026-07-03 19:30:41 +02:00
# sdk, cli & web build
2025-08-29 12:27:24 +02:00
cd " $SRC_DIR "
2025-09-18 15:15:54 -04:00
echo "packageImportMethod: hardlink" >>./pnpm-workspace.yaml
2025-10-15 16:20:56 -04:00
unset SHARP_FORCE_GLOBAL_LIBVIPS
2026-07-03 19:30:41 +02:00
$STD pnpm --filter @immich/sdk --filter immich-web --filter @immich/cli build
$STD pnpm --filter @immich/cli --prod --no-optional deploy " $APP_DIR " /cli
2025-08-29 12:27:24 +02:00
cp -a web/build " $APP_DIR " /www
cp LICENSE " $APP_DIR "
2026-01-31 20:07:27 -05:00
[[ -f " $INSTALL_DIR " /start.sh ]] && mv " $INSTALL_DIR " /start.sh " $APP_DIR " /bin
2025-11-20 12:08:25 -05:00
# plugins
cd " $SRC_DIR "
2026-07-03 19:30:41 +02:00
export MISE_TRUSTED_CONFIG_PATHS = " $SRC_DIR " /mise.toml
export MISE_DISABLE_TOOLS = github:jellyfin/jellyfin-ffmpeg
2026-08-07 10:10:35 +02:00
mise_ok = 0
for i in 1 2 3; do
$STD mise install && {
mise_ok = 1
break
}
msg_warn "mise install failed (attempt $i /3) - retrying"
sleep 5
done
[[ " $mise_ok " -eq 1 ]] || exit 1
2026-07-03 19:30:41 +02:00
export PATH = " $( mise bin-paths 2>/dev/null | tr '\n' ':' ) $PATH "
if ! command -v extism-js >/dev/null 2>& 1; then
# extism-js ships as a bare gzip-compressed single binary (.gz) that
# fetch_and_deploy_gh_release cannot deploy; fetch + gunzip it directly.
EXTISM_ARCH = " $( arch_resolve x86_64 aarch64) "
curl_download /tmp/extism-js.gz "https://github.com/extism/js-pdk/releases/download/v1.6.0/extism-js- ${ EXTISM_ARCH } -linux-v1.6.0.gz"
gunzip -f /tmp/extism-js.gz
install -m 0755 /tmp/extism-js /usr/local/bin/extism-js
rm -f /tmp/extism-js
fi
if ! command -v wasm-merge >/dev/null 2>& 1; then
# extism-js needs binaryen's `wasm-merge` to build the plugin wasm. mise
# 2026.7.0's github backend no longer exposes `wasm-merge` on PATH (ubi only
# extracts a single binary), so install the pinned binaryen release from
# mise.toml directly. The extracted bin/ keeps libbinaryen.so alongside it.
BINARYEN_VERSION = " $( grep -oiP 'binaryen"\s*=\s*"\Kversion_[0-9]+' " $SRC_DIR " /mise.toml | head -n1) "
[[ -z " $BINARYEN_VERSION " ]] && BINARYEN_VERSION = "version_124"
BINARYEN_ARCH = " $( arch_resolve x86_64 aarch64) "
curl_download /tmp/binaryen.tar.gz "https://github.com/WebAssembly/binaryen/releases/download/ ${ BINARYEN_VERSION } /binaryen- ${ BINARYEN_VERSION } - ${ BINARYEN_ARCH } -linux.tar.gz"
tar -xzf /tmp/binaryen.tar.gz -C /opt
rm -f /tmp/binaryen.tar.gz
export PATH = "/opt/binaryen- ${ BINARYEN_VERSION } /bin: $PATH "
fi
$STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core install --frozen-lockfile
$STD mise exec -- pnpm --filter @immich/sdk --filter @immich/plugin-sdk --filter @immich/plugin-core build
2025-11-20 12:08:25 -05:00
mkdir -p " $PLUGIN_DIR "
2026-07-03 19:30:41 +02:00
cp -r ./packages/plugin-core/dist " $PLUGIN_DIR " /dist
cp ./packages/plugin-core/manifest.json " $PLUGIN_DIR "
2026-01-29 08:37:54 -05:00
msg_ok "Updated Immich server, web, cli and plugins"
2025-08-29 12:27:24 +02:00
cd " $SRC_DIR " /machine-learning
2026-03-08 19:05:29 -04:00
mkdir -p " $ML_DIR "
2026-03-26 12:24:26 +01:00
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich " $INSTALL_DIR "
find " $INSTALL_DIR " -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich " ${ UPLOAD_DIR :- $INSTALL_DIR /upload } " 2>/dev/null || true
2025-10-01 04:39:20 -04:00
chown immich:immich ./uv.lock
2025-08-29 12:27:24 +02:00
export VIRTUAL_ENV = " ${ ML_DIR } " /ml-venv
if [[ -f ~/.openvino ]] ; then
2026-03-16 17:32:16 +01:00
ML_PYTHON = "python3.13"
msg_info "Pre-installing Python ${ ML_PYTHON } for machine-learning"
for attempt in $( seq 1 3) ; do
2026-07-03 19:30:41 +02:00
$STD sudo --preserve-env= VIRTUAL_ENV -Pnu immich uv python install " ${ ML_PYTHON } " && break
2026-03-16 17:32:16 +01:00
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
done
msg_ok "Pre-installed Python ${ ML_PYTHON } "
2026-03-20 09:14:24 -04:00
msg_info "Updating Intel OpenVINO machine-learning"
2026-03-16 20:41:21 +01:00
for attempt in $( seq 1 3) ; do
2026-07-03 19:30:41 +02:00
$STD sudo --preserve-env= VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p " ${ ML_PYTHON } " --managed-python && break
2026-03-16 20:41:21 +01:00
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
done
2026-06-22 23:35:14 +10:00
patchelf --clear-execstack " ${ VIRTUAL_ENV } /lib/python3.13/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-313- $( arch_resolve "x86_64" "aarch64" ) -linux-gnu.so"
2026-03-20 09:14:24 -04:00
msg_ok "Updated Intel OpenVINO machine-learning"
2025-08-29 12:27:24 +02:00
else
2026-03-16 17:32:16 +01:00
ML_PYTHON = "python3.11"
msg_info "Pre-installing Python ${ ML_PYTHON } for machine-learning"
for attempt in $( seq 1 3) ; do
2026-07-03 19:30:41 +02:00
$STD sudo --preserve-env= VIRTUAL_ENV -Pnu immich uv python install " ${ ML_PYTHON } " && break
2026-03-16 17:32:16 +01:00
[[ $attempt -lt 3 ]] && msg_warn "Python download attempt $attempt failed, retrying..." && sleep 5
done
msg_ok "Pre-installed Python ${ ML_PYTHON } "
2025-08-29 12:27:24 +02:00
msg_info "Updating machine-learning"
2026-03-16 20:41:21 +01:00
for attempt in $( seq 1 3) ; do
2026-07-03 19:30:41 +02:00
$STD sudo --preserve-env= VIRTUAL_ENV,UV_HTTP_TIMEOUT -Pnu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p " ${ ML_PYTHON } " --managed-python && break
2026-03-16 20:41:21 +01:00
[[ $attempt -lt 3 ]] && msg_warn "uv sync attempt $attempt failed, retrying..." && sleep 10
done
2025-08-29 12:27:24 +02:00
msg_ok "Updated machine-learning"
fi
cd " $SRC_DIR "
cp -a machine-learning/{ ann,immich_ml} " $ML_DIR "
2026-01-31 20:07:27 -05:00
[[ -f " $INSTALL_DIR " /ml_start.sh ]] && mv " $INSTALL_DIR " /ml_start.sh " $ML_DIR "
2026-07-03 19:30:41 +02:00
# Regenerate ml_start.sh if it is missing (e.g. lost by a previously interrupted update),
# otherwise immich-ml.service fails to start with status=203/EXEC
if [[ ! -f " $ML_DIR " /ml_start.sh ]] ; then
cat <<EOF >"$ML_DIR"/ml_start.sh
#!/usr/bin/env bash
cd ${ML_DIR}
. ${VIRTUAL_ENV}/bin/activate
set -a
. ${INSTALL_DIR}/.env
set +a
python3 -m immich_ml
EOF
chmod +x " $ML_DIR " /ml_start.sh
fi
2026-01-31 20:07:27 -05:00
[[ -f ~/.openvino ]] && sed -i "/intra_op/s/int = 0/int = os.cpu_count() or 0/" " $ML_DIR " /immich_ml/config.py
2025-08-29 12:27:24 +02:00
ln -sf " $APP_DIR " /resources " $INSTALL_DIR "
cd " $APP_DIR "
grep -rl /usr/src | xargs -n1 sed -i "s|\/usr/src| $INSTALL_DIR |g"
grep -rlE "'/build'" | xargs -n1 sed -i "s|'/build'|' $APP_DIR '|g"
sed -i "s@\"/cache\"@\" $INSTALL_DIR /cache\"@g" " $ML_DIR " /immich_ml/config.py
2026-07-30 14:05:25 -04:00
[[ ! -f " $GEO_DIR /countryInfo.txt" ]] && curl_with_retry "https://download.geonames.org/export/dump/countryInfo.txt" "countryInfo.txt"
2025-08-29 12:27:24 +02:00
ln -s " ${ UPLOAD_DIR :- /opt/immich/upload } " " $APP_DIR " /upload
ln -s " ${ UPLOAD_DIR :- /opt/immich/upload } " " $ML_DIR " /upload
2026-09-24 11:29:18 +02:00
ln -sfn " $GEO_DIR " " $APP_DIR /geodata"
2026-01-31 20:07:27 -05:00
[[ ! -f /usr/bin/immich ]] && ln -sf " $APP_DIR " /cli/bin/immich /usr/bin/immich
[[ ! -f /usr/bin/immich-admin ]] && ln -sf " $APP_DIR " /bin/immich-admin /usr/bin/immich-admin
2025-08-29 12:27:24 +02:00
2026-03-26 12:24:26 +01:00
if ! grep -q '^DB_HOSTNAME=' " $INSTALL_DIR " /.env; then
sed -i '/^DB_DATABASE_NAME/a DB_HOSTNAME=127.0.0.1' " $INSTALL_DIR " /.env
fi
2026-04-08 01:21:07 -04:00
if ! grep -q 'HELMET_FILE' " $INSTALL_DIR " /.env; then
2026-04-11 23:55:07 +02:00
sed -i -e '$a\' " $INSTALL_DIR " /.env
2026-04-08 01:21:07 -04:00
echo "IMMICH_HELMET_FILE=true" >>" $INSTALL_DIR " /.env
fi
2026-03-26 12:24:26 +01:00
if grep -q 'ExecStart=/usr/bin/node' /etc/systemd/system/immich-web.service; then
sed -i '/^EnvironmentFile=/d' /etc/systemd/system/immich-web.service
sed -i "s|^ExecStart=.*|ExecStart= ${ APP_DIR } /bin/start.sh|" /etc/systemd/system/immich-web.service
systemctl daemon-reload
fi
2026-07-12 11:48:43 -04:00
# MickLesk temporary patch for HEIC thumbnail gen
msg_info "Patching media.repository.js"
MEDIA_REPO_JS = "/opt/immich/app/dist/repositories/media.repository.js"
if [[ -f " $MEDIA_REPO_JS " ]] ; then
python3 - <<'PY'
from pathlib import Path
p = Path('/opt/immich/app/dist/repositories/media.repository.js')
s = p.read_text()
old = "(0, sharp_1.default)(input).metadata()"
new = "(0, sharp_1.default)(input, { unlimited: true, limitInputPixels: false }).metadata()"
if new in s:
print('hotfix already there')
2026-07-12 18:24:19 +02:00
elif old in s:
2026-07-12 11:48:43 -04:00
p.write_text(s.replace(old, new, 1))
print('hotfix applied')
2026-07-12 18:24:19 +02:00
else:
2026-07-12 11:48:43 -04:00
print('pattern not found, skipped')
PY
fi
msg_ok "Patched media.repository.js"
2026-03-26 12:24:26 +01:00
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich " $INSTALL_DIR "
find " $INSTALL_DIR " -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich " ${ UPLOAD_DIR :- $INSTALL_DIR /upload } " 2>/dev/null || true
2026-01-30 11:14:06 +01:00
if [[ " ${ MAINT_MODE :- 0 } " == 1 ]] ; then
2026-01-29 14:35:00 -05:00
msg_info "Disabling Maintenance Mode"
cd /opt/immich/app/bin
2026-03-29 22:16:16 +02:00
$STD ./immich-admin disable-maintenance-mode || true
2026-01-29 14:35:00 -05:00
unset MAINT_MODE
$STD cd -
msg_ok "Disabled Maintenance Mode"
fi
2025-08-29 12:27:24 +02:00
systemctl restart immich-ml immich-web
2026-02-06 11:28:15 -05:00
[[ -f /etc/systemd/system/immich-proxy.service ]] && systemctl restart immich-proxy
2026-01-29 08:37:54 -05:00
msg_ok "Updated successfully!"
2025-08-14 14:20:21 -04:00
fi
2025-08-29 14:16:18 +02:00
exit
2025-06-01 10:50:08 +02:00
}
2025-07-11 02:35:45 -04:00
function compile_libjxl() {
SOURCE = ${ SOURCE_DIR } /libjxl
2026-08-21 07:55:32 +02:00
LIBJXL_REVISION = " $( jq -cr '.revision' " $BASE_DIR " /server/sources/libjxl.json) "
2025-09-13 03:20:22 -04:00
if [[ " $LIBJXL_REVISION " != " $( grep 'libjxl' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ; then
2025-07-11 02:35:45 -04:00
msg_info "Recompiling libjxl"
2026-01-31 20:07:27 -05:00
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
2025-07-11 02:35:45 -04:00
$STD git clone https://github.com/libjxl/libjxl.git " $SOURCE "
cd " $SOURCE "
$STD git reset --hard " $LIBJXL_REVISION "
$STD git submodule update --init --recursive --depth 1 --recommend-shallow
mkdir build
cd build
$STD cmake \
-DCMAKE_BUILD_TYPE= Release \
-DBUILD_TESTING= OFF \
-DJPEGXL_ENABLE_DOXYGEN= OFF \
-DJPEGXL_ENABLE_MANPAGES= OFF \
-DJPEGXL_ENABLE_BENCHMARK= OFF \
-DJPEGXL_ENABLE_EXAMPLES= OFF \
-DJPEGXL_FORCE_SYSTEM_BROTLI= ON \
-DJPEGXL_FORCE_SYSTEM_HWY= ON \
2026-08-21 07:55:32 +02:00
-DJPEGXL_ENABLE_HWY_AVX3= ON \
-DJPEGXL_ENABLE_HWY_AVX3_ZEN4= ON \
-DJPEGXL_ENABLE_HWY_SVE= OFF \
-DJPEGXL_ENABLE_HWY_SVE2= OFF \
-DJPEGXL_ENABLE_HWY_SVE2_128= ON \
2025-07-11 02:35:45 -04:00
-DJPEGXL_ENABLE_PLUGINS= ON \
2026-08-21 07:55:32 +02:00
..
$STD cmake --build . -- -j" $( nproc) "
$STD cmake --install .
ldconfig /usr/local/lib
$STD make clean
cd " $STAGING_DIR "
rm -rf " $SOURCE " /{ build,third_party}
sed -i "s/libjxl: .* $/libjxl: $LIBJXL_REVISION /" ~/.immich_library_revisions
msg_ok "Recompiled libjxl"
fi
}
function compile_jpegli() {
SOURCE = ${ SOURCE_DIR } /jpegli
JPEGLI_LIBJPEG_LIBRARY_SOVERSION = "62"
JPEGLI_LIBJPEG_LIBRARY_VERSION = "62.3.0"
JPEGLI_REVISION = " $( jq -cr '.revision' " $BASE_DIR " /server/sources/jpegli.json) "
if [[ " $JPEGLI_REVISION " != " $( grep 'jpegli' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ; then
msg_info "Recompiling jpegli"
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
$STD git clone https://github.com/google/jpegli.git " $SOURCE "
cd " $SOURCE "
$STD git reset --hard " $JPEGLI_REVISION "
$STD git submodule update --init --depth 1 --recommend-shallow third_party/libjpeg-turbo
$STD git apply -3 " $BASE_DIR " /server/sources/jpegli-patches/jpegli-empty-dht-marker.patch
$STD git apply -3 " $BASE_DIR " /server/sources/jpegli-patches/jpegli-icc-warning.patch
mkdir build
cd build
$STD cmake \
-DCMAKE_BUILD_TYPE= Release \
-DBUILD_TESTING= OFF \
-DJPEGLI_ENABLE_DOXYGEN= OFF \
-DJPEGLI_ENABLE_MANPAGES= OFF \
-DJPEGLI_ENABLE_BENCHMARK= OFF \
-DJPEGLI_ENABLE_TOOLS= OFF \
-DJPEGLI_ENABLE_DEVTOOLS= OFF \
-DJPEGLI_ENABLE_FUZZERS= OFF \
-DJPEGLI_ENABLE_JNI= OFF \
-DJPEGLI_ENABLE_OPENEXR= OFF \
-DJPEGLI_ENABLE_SJPEG= OFF \
-DJPEGLI_ENABLE_SKCMS= OFF \
-DJPEGLI_FORCE_SYSTEM_HWY= ON \
-DJPEGLI_FORCE_SYSTEM_LCMS2= ON \
-DJPEGLI_ENABLE_JPEGLI_LIBJPEG= ON \
-DJPEGLI_INSTALL_JPEGLI_LIBJPEG= ON \
-DJPEGLI_ENABLE_HWY_AVX3= ON \
-DJPEGLI_ENABLE_HWY_AVX3_ZEN4= ON \
-DJPEGLI_ENABLE_HWY_SVE= OFF \
-DJPEGLI_ENABLE_HWY_SVE2= OFF \
-DJPEGLI_ENABLE_HWY_SVE2_128= ON \
2025-07-11 02:35:45 -04:00
-DJPEGLI_LIBJPEG_LIBRARY_SOVERSION= " $JPEGLI_LIBJPEG_LIBRARY_SOVERSION " \
-DJPEGLI_LIBJPEG_LIBRARY_VERSION= " $JPEGLI_LIBJPEG_LIBRARY_VERSION " \
-DLIBJPEG_TURBO_VERSION_NUMBER= 2001005 \
..
$STD cmake --build . -- -j" $( nproc) "
$STD cmake --install .
ldconfig /usr/local/lib
$STD make clean
cd " $STAGING_DIR "
rm -rf " $SOURCE " /{ build,third_party}
2026-08-21 07:55:32 +02:00
sed -i "s/jpegli: .* $/jpegli: $JPEGLI_REVISION /" ~/.immich_library_revisions
msg_ok "Recompiled jpegli"
2025-07-11 02:35:45 -04:00
fi
}
function compile_libheif() {
SOURCE = ${ SOURCE_DIR } /libheif
2026-02-02 13:01:17 +01:00
ensure_dependencies libaom-dev
2026-09-03 14:22:16 -04:00
LIBHEIF_REVISION = "ac1cb05c39008f01525c991ff8b88f84ddf70fd2"
2026-04-14 15:19:16 -04:00
# : "${LIBHEIF_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libheif.json)}"
2025-07-11 02:35:45 -04:00
if [[ " ${ update :- } " ]] || [[ " $LIBHEIF_REVISION " != " $( grep 'libheif' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ; then
msg_info "Recompiling libheif"
2026-01-31 20:07:27 -05:00
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
2025-07-11 02:35:45 -04:00
$STD git clone https://github.com/strukturag/libheif.git " $SOURCE "
cd " $SOURCE "
$STD git reset --hard " $LIBHEIF_REVISION "
mkdir build
cd build
$STD cmake --preset= release-noplugins \
-DWITH_DAV1D= ON \
-DENABLE_PARALLEL_TILE_DECODING= ON \
-DWITH_LIBSHARPYUV= ON \
-DWITH_LIBDE265= ON \
-DWITH_AOM_DECODER= OFF \
-DWITH_AOM_ENCODER= ON \
-DWITH_X265= OFF \
-DWITH_EXAMPLES= OFF \
..
2026-01-31 20:07:27 -05:00
$STD make install -j" $( nproc) "
2025-07-11 02:35:45 -04:00
ldconfig /usr/local/lib
$STD make clean
cd " $STAGING_DIR "
rm -rf " $SOURCE " /build
2025-08-01 15:06:03 -04:00
sed -i "s/libheif: .* $/libheif: $LIBHEIF_REVISION /" ~/.immich_library_revisions
2025-07-11 02:35:45 -04:00
msg_ok "Recompiled libheif"
fi
}
function compile_libraw() {
SOURCE = ${ SOURCE_DIR } /libraw
2026-09-03 14:22:16 -04:00
LIBRAW_REVISION = "e419de08001de28ae6988ecb22df47e52b9c5eaa"
2026-04-14 15:19:16 -04:00
# : "${LIBRAW_REVISION:=$(jq -cr '.revision' "$BASE_DIR"/server/sources/libraw.json)}"
2025-09-13 03:20:22 -04:00
if [[ " $LIBRAW_REVISION " != " $( grep 'libraw' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ; then
2025-07-11 02:35:45 -04:00
msg_info "Recompiling libraw"
2026-01-31 20:07:27 -05:00
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
2026-03-04 06:49:45 +02:00
$STD git clone https://github.com/LibRaw/LibRaw.git " $SOURCE "
2025-07-11 02:35:45 -04:00
cd " $SOURCE "
$STD git reset --hard " $LIBRAW_REVISION "
$STD autoreconf --install
2026-01-27 11:38:16 -05:00
$STD ./configure --disable-examples
2025-07-11 02:35:45 -04:00
$STD make -j" $( nproc) "
$STD make install
ldconfig /usr/local/lib
$STD make clean
cd " $STAGING_DIR "
2025-08-01 15:06:03 -04:00
sed -i "s/libraw: .* $/libraw: $LIBRAW_REVISION /" ~/.immich_library_revisions
2025-07-11 02:35:45 -04:00
msg_ok "Recompiled libraw"
fi
}
function compile_imagemagick() {
SOURCE = $SOURCE_DIR /imagemagick
2025-09-18 15:15:54 -04:00
: " ${ IMAGEMAGICK_REVISION := $( jq -cr '.revision' " $BASE_DIR " /server/sources/imagemagick.json) } "
if [[ " $IMAGEMAGICK_REVISION " != " $( grep 'imagemagick' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ||
! grep -q 'DMAGICK_LIBRAW' /usr/local/lib/ImageMagick-7*/config-Q16HDRI/configure.xml; then
2025-07-11 02:35:45 -04:00
msg_info "Recompiling ImageMagick"
2026-01-31 20:07:27 -05:00
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
2025-07-11 02:35:45 -04:00
$STD git clone https://github.com/ImageMagick/ImageMagick.git " $SOURCE "
cd " $SOURCE "
$STD git reset --hard " $IMAGEMAGICK_REVISION "
2025-09-18 15:15:54 -04:00
$STD ./configure --with-modules CPPFLAGS = "-DMAGICK_LIBRAW_VERSION_TAIL=202502"
2025-07-11 02:35:45 -04:00
$STD make -j" $( nproc) "
$STD make install
ldconfig /usr/local/lib
$STD make clean
cd " $STAGING_DIR "
2025-08-01 15:06:03 -04:00
sed -i "s/imagemagick: .* $/imagemagick: $IMAGEMAGICK_REVISION /" ~/.immich_library_revisions
2025-07-11 02:35:45 -04:00
msg_ok "Recompiled ImageMagick"
fi
}
function compile_libvips() {
SOURCE = $SOURCE_DIR /libvips
2026-08-21 07:55:32 +02:00
LIBVIPS_REVISION = " $( jq -cr '.revision' " $BASE_DIR " /server/sources/libvips.json) "
2025-09-13 03:20:22 -04:00
if [[ " $LIBVIPS_REVISION " != " $( grep 'libvips' ~/.immich_library_revisions | awk '{print $2}' ) " ]] ; then
2025-07-11 02:35:45 -04:00
msg_info "Recompiling libvips"
2026-01-31 20:07:27 -05:00
[[ -d " $SOURCE " ]] && rm -rf " $SOURCE "
2025-07-11 02:35:45 -04:00
$STD git clone https://github.com/libvips/libvips.git " $SOURCE "
cd " $SOURCE "
$STD git reset --hard " $LIBVIPS_REVISION "
2026-07-14 03:32:29 -04:00
$STD git apply " $BASE_DIR " /server/sources/libvips-patches/0001-put-other-loaders-ahead-of-dcrawload.patch
2025-07-11 02:35:45 -04:00
$STD meson setup build --buildtype= release --libdir= lib -Dintrospection= disabled -Dtiff= disabled
cd build
$STD ninja install
ldconfig /usr/local/lib
cd " $STAGING_DIR "
rm -rf " $SOURCE " /build
2025-08-01 15:06:03 -04:00
sed -i "s/libvips: .* $/libvips: $LIBVIPS_REVISION /" ~/.immich_library_revisions
2025-07-11 02:35:45 -04:00
msg_ok "Recompiled libvips"
fi
}
2025-06-01 10:50:08 +02:00
start
build_container
description
2026-01-06 22:57:40 +01:00
msg_ok "Completed successfully!\n"
2025-06-01 10:50:08 +02:00
echo -e " ${ CREATING }${ GN }${ APP } setup has been successfully initialized! ${ CL } "
2026-06-03 11:03:13 +02:00
echo -e " ${ INFO }${ YW } Access it using the following URL: ${ CL } "
echo -e " ${ GATEWAY }${ BGN } http:// ${ IP } :2283 ${ CL } "