From 9a7034ede1f2f4289a3ffb9be16d37deb8508187 Mon Sep 17 00:00:00 2001 From: Juhyung Park Date: Sat, 2 Mar 2024 02:07:58 +0900 Subject: [PATCH] Initial commit Signed-off-by: Juhyung Park --- README.md | 108 ++++++++++++++++++++++ env | 24 +++++ immich-machine-learning.service | 20 ++++ immich-microservices.service | 22 +++++ immich.service | 24 +++++ install.sh | 158 ++++++++++++++++++++++++++++++++ 6 files changed, 356 insertions(+) create mode 100644 README.md create mode 100644 env create mode 100644 immich-machine-learning.service create mode 100644 immich-microservices.service create mode 100644 immich.service create mode 100755 install.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf5fb9a --- /dev/null +++ b/README.md @@ -0,0 +1,108 @@ +# Native Immich + +This repository provides instructions and helper scripts to install [Immich](https://github.com/immich-app/immich) without Docker, natively. + +### Notes + + * This is tested on Ubuntu 22.04 (on both x86 and aarch64) as the host distro, but it will be similar on other distros. + + * This guide installs Immich to `/var/lib/immich`. To change it, replace it to the directory you want in this README and `install.sh`'s `$IMMICH_PATH`. + + * The [install.sh](install.sh) script currently is using Immich v1.97.0 with some additional minor fixes. It should be noted that due to the fast-evolving nature of Immich, the install script may get broken if you replace the `$TAG` to something more recent. + + * `mimalloc` is deliberately disabled as this is a native install and sharing system library makes more sense. + + * Microservice and machine-learning's host is opened to 0.0.0.0 in the default configuration. This behavior is changed to only accept 127.0.0.1 during installation. Only the main Immich service's port, 3001, is opened to 0.0.0.0. + + * Only the basic CPU configuration is used. Hardware-acceleration such as CUDA is unsupported. + +## 1. Install dependencies + + * [Node.js](https://github.com/nodesource/distributions) + + * [PostgreSQL](https://www.postgresql.org/download/linux/ubuntu) + + * [Redis](https://redis.io/docs/install/install-redis/install-redis-on-linux) + +As the time of writing, Node.js v20 LTS, PostgreSQL 16 and Redis 7.2.4 was used. + + * [pgvector](https://github.com/pgvector/pgvector) + +As the time of writing, pgvector v0.6.0 was used. + +You need the `postgresql-server-dev(-16)` package installed to build and install pgvector. + +It comes with a lot of other dependencies, but you can remove it all after pgvector is built and installed. + +It is recommended to strip the `vector.so` to reduce memory footprint: + +``` bash +sudo strip /usr/lib/postgresql/*/lib/vector.so +``` + +### Other APT packages + +``` bash +sudo apt install python3-venv python3-dev +``` + +A separate Python's virtualenv will be stored to `/var/lib/immich`. + +## 2. Prepare `immich` user + +This guide isolates Immich to run on a separate `immich` user. + +This provides basic permission isolation and protection. + +``` bash +sudo adduser \ + --home /var/lib/immich/home \ + --shell=/sbin/nologin \ + --no-create-home \ + --disabled-password \ + --disabled-login \ + immich +sudo mkdir -p /var/lib/immich +sudo chown immich:immich /var/lib/immich +sudo chmod 700 /var/lib/immich +``` + +## 3. Prepare PostgreSQL DB + +Create a strong random string to be used with PostgreSQL immich database. + +You need to save this and write to the `env` file later. + +``` bash +sudo -u postgres psql +postgres=# create database immich; +postgres=# create user immich with encrypted password 'YOUR_STRONG_RANDOM_PW'; +postgres=# grant all privileges on database immich to immich; +postgrse=# ALTER USER immich WITH SUPERUSER; +postgres=# \q +``` + +## 4. Prepare `env` + +Save the [env](env) file to `/var/lib/immich`, and configure on your own. + +You'll only have to set `DB_PASSWORD`. + +``` bash +sudo cp env /var/lib/immich +sudo chown immich:immich /var/lib/immich/env +``` + +## 5. Build and install Immich + +Clone this repository to somewhere anyone can access (like /tmp) and run `install.sh` as root. + +Anytime Immich is updated, all you have to do is run it again. + +## Done! + +Your Immich installation should be running at :3001 port. + +Immich will additionally use 3002 and 3003 ports, but those will only listen from localhost (127.0.0.1). + +Please add firewall rules and apply https proxy and secure your Immich instance. diff --git a/env b/env new file mode 100644 index 0000000..e6109c6 --- /dev/null +++ b/env @@ -0,0 +1,24 @@ +# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables + +# Connection secret for postgres. You should change it to a random password +DB_PASSWORD=YOUR_STRONG_RANDOM_PW + +# The values below this line do not need to be changed +################################################################################### +NODE_ENV=production + +DB_USERNAME=immich +DB_DATABASE_NAME=immich +DB_VECTOR_EXTENSION=pgvector + +# The location where your uploaded files are stored +UPLOAD_LOCATION=./library + +# The Immich version to use. You can pin this to a specific version like "v1.71.0" +IMMICH_VERSION=release + +# Hosts & ports +DB_HOSTNAME=127.0.0.1 +MACHINE_LEARNING_HOST=127.0.0.1 +IMMICH_MACHINE_LEARNING_URL=http://127.0.0.1:3003 +REDIS_HOSTNAME=127.0.0.1 diff --git a/immich-machine-learning.service b/immich-machine-learning.service new file mode 100644 index 0000000..07f3e73 --- /dev/null +++ b/immich-machine-learning.service @@ -0,0 +1,20 @@ +[Unit] +Description=immich machine-learning +Documentation=https://github.com/immich-app/immich + +[Service] +User=immich +Group=immich +Type=simple +Restart=on-failure + +WorkingDirectory=/var/lib/immich/app +EnvironmentFile=/var/lib/immich/env +ExecStart=/var/lib/immich/app/machine-learning/start.sh + +SyslogIdentifier=immich-machine-learning +StandardOutput=append:/var/log/immich/immich-machine-learning.log +StandardError=append:/var/log/immich/immich-machine-learning.log + +[Install] +WantedBy=multi-user.target diff --git a/immich-microservices.service b/immich-microservices.service new file mode 100644 index 0000000..686f7dd --- /dev/null +++ b/immich-microservices.service @@ -0,0 +1,22 @@ +[Unit] +Description=immich microservices +Documentation=https://github.com/immich-app/immich +Requires=redis-server.service +Requires=postgresql.service + +[Service] +User=immich +Group=immich +Type=simple +Restart=on-failure + +WorkingDirectory=/var/lib/immich/app +EnvironmentFile=/var/lib/immich/env +ExecStart=node /var/lib/immich/app/dist/main microservices + +SyslogIdentifier=immich-microservices +StandardOutput=append:/var/log/immich/immich-microservices.log +StandardError=append:/var/log/immich/immich-microservices.log + +[Install] +WantedBy=multi-user.target diff --git a/immich.service b/immich.service new file mode 100644 index 0000000..a15e1ff --- /dev/null +++ b/immich.service @@ -0,0 +1,24 @@ +[Unit] +Description=immich server +Documentation=https://github.com/immich-app/immich +Requires=redis-server.service +Requires=postgresql.service +Requires=immich-machine-learning.service +Requires=immich.service + +[Service] +User=immich +Group=immich +Type=simple +Restart=on-failure + +WorkingDirectory=/var/lib/immich/app +EnvironmentFile=/var/lib/immich/env +ExecStart=node /var/lib/immich/app/dist/main immich + +SyslogIdentifier=immich +StandardOutput=append:/var/log/immich/immich.log +StandardError=append:/var/log/immich/immich.log + +[Install] +WantedBy=multi-user.target diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..4707717 --- /dev/null +++ b/install.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +set -xeuo pipefail + +#TAG=v1.97.0 +TAG=3b772a772 + +IMMICH_PATH=/var/lib/immich +APP=$IMMICH_PATH/app + +if [[ "$USER" != "immich" ]]; then + # Disable systemd services, if installed + ( + for i in immich*.service; do + systemctl stop $i && \ + systemctl disable $i && \ + rm /etc/systemd/system/$i && + systemctl daemon-reload + done + ) || true + + mkdir -p $IMMICH_PATH + chown immich:immich $IMMICH_PATH + + mkdir -p /var/log/immich + chown immich:immich /var/log/immich + + echo "Restarting the script as user immich" + exec sudo -u immich $0 $* +fi + +BASEDIR=$(dirname "$0") + +rm -rf $APP +mkdir -p $APP + +# Wipe npm, pypoetry, etc +# This expects immich user's home directory to be on $IMMICH_PATH/home +rm -rf $IMMICH_PATH/home +mkdir -p $IMMICH_PATH/home + +TMP=/tmp/immich-$(uuidgen) +git clone https://github.com/immich-app/immich $TMP +cd $TMP +git reset --hard $TAG + +# immich-server +cd server +npm ci +npm run build +npm prune --omit=dev --omit=optional +cd - + +cd open-api/typescript-sdk +npm ci +npm run build +cd - + +cd web +npm ci +npm run build +cd - + +cp -a server/node_modules server/dist server/bin $APP/ +cp -a web/build $APP/www +cp -a server/resources server/package.json server/package-lock.json $APP/ +cp -a server/start*.sh $APP/ +cp -a LICENSE $APP/ +cd $APP +npm cache clean --force +cd - + +# immich-machine-learning +mkdir -p $APP/machine-learning +python3 -m venv $APP/machine-learning/venv +( + # Initiate subshell to setup venv + . $APP/machine-learning/venv/bin/activate + pip3 install poetry + cd machine-learning + # pip install poetry + poetry install --no-root --with dev --with cpu + cd .. +) +cp -a machine-learning/ann machine-learning/start.sh machine-learning/app $APP/machine-learning/ + +# Replace /usr/src +cd $APP +grep -Rl /usr/src | xargs -n1 sed -i -e "s@/usr/src@$IMMICH_PATH@g" +ln -sf $IMMICH_PATH/app/resources $IMMICH_PATH/ +mkdir -p $IMMICH_PATH/cache +sed -i -e "s@\"/cache\"@\"$IMMICH_PATH/cache\"@g" $APP/machine-learning/app/config.py + +# Install sharp +cd $APP +npm install sharp + +# Setup upload directory +mkdir -p $IMMICH_PATH/upload +ln -s $IMMICH_PATH/upload $APP/ +ln -s $IMMICH_PATH/upload $APP/machine-learning/ + +# Use 127.0.0.1 for microservices +sed -i -e "s@app.listen(port)@app.listen(port, '127.0.0.1')@g" $APP/dist/microservices/main.js + +# Custom start.sh script +cat < $APP/start.sh +#!/bin/bash + +set -a +. $IMMICH_PATH/env +set +a + +cd $APP +exec node $APP/dist/main "\$@" +EOF + +cat < $APP/machine-learning/start.sh +#!/bin/bash + +set -a +. $IMMICH_PATH/env +set +a + +cd $APP/machine-learning +. venv/bin/activate + +: "\${MACHINE_LEARNING_HOST:=127.0.0.1}" +: "\${MACHINE_LEARNING_PORT:=3003}" +: "\${MACHINE_LEARNING_WORKERS:=1}" +: "\${MACHINE_LEARNING_WORKER_TIMEOUT:=120}" + +exec gunicorn app.main:app \ + -k app.config.CustomUvicornWorker \ + -w "\$MACHINE_LEARNING_WORKERS" \ + -b "\$MACHINE_LEARNING_HOST":"\$MACHINE_LEARNING_PORT" \ + -t "\$MACHINE_LEARNING_WORKER_TIMEOUT" \ + --log-config-json log_conf.json \ + --graceful-timeout 0 +EOF + +# Cleanup +rm -rf $TMP + +# Installing systemd services +echo "Installing systemd services" + +cd "$BASEDIR" +sudo cp immich*.service /etc/systemd/system/ +sudo systemctl daemon-reload +for i in immich*.service; do + sudo systemctl enable $i + sudo systemctl start $i +done + +echo +echo "Done" +echo