cubeshipd/immich
Immich
Immich is a self-hosted photo and video backup: phone apps that upload in the background, a web timeline, albums and sharing, and search by faces, places and what is in the picture. This template installs it on a Cubeship instance.
Immich on Cubeship
Immich is a self-hosted photo and video backup: phone apps that upload in the background, a web timeline, albums and sharing, and search by faces, places and what is in the picture. This template installs it on a Cubeship instance.
What it creates
- immich — the Immich server
v3.2.0: the web app, the API the phone apps talk to, and the background jobs that make thumbnails and transcode videos. It answers on the domain you choose and keeps every upload in a volume at/data. - machine-learning — Immich's machine learning
v3.2.0, on the CPU: smart search, face detection and recognition, and text in images. It has no domain, listens on port3003inside the instance, and keeps the models it downloads in a volume at/cache. - immich-db — a managed Postgres 17 with the
pgvectorandvectorchordextensions, where Immich keeps everything but the files themselves. - immich-redis — a managed Redis 7.4, where Immich queues its jobs.
Machine learning is deployed first, then the server.
It needs Cubeship 0.9.0 or newer, and an admin to install it: creating a managed database is an admin's.
The database
Immich stores its search and face embeddings as pgvector columns and indexes
them with VectorChord. Both are extensions Cubeship can create a managed
Postgres with, so there is no database container to build here and no volume to
back up separately — it is a database the instance runs, backs up and charts
like any other.
That is a change from earlier releases of this template, which ran Immich's own
Postgres image as an app. An existing installation is not migrated. Its
postgres app and the volume under it stay exactly where they are; moving to
the managed database means installing this template fresh and moving the data
across with pg_dump and psql.
What you are asked
| Input | What to give |
|---|---|
| Where Immich answers | A domain you control, pointed at your instance. The phone apps connect to it. |
The database password is not asked for: the instance generates one and hands it to Immich. Read it from the database's page if you ever need it.
After installing
- Open
https://<your domain>straight away. Immich has no default account: the first person to sign up becomes the admin. - In the Immich app on your phone, enter
https://<your domain>as the server URL and sign in.
Immich finds the machine learning app through IMMICH_MACHINE_LEARNING_URL on
the immich app. That is only the default of the setting under
Administration → Settings → Machine Learning: a URL saved there wins.
The first time a job needs a model, machine learning downloads it from Hugging Face, so the server needs to reach the internet. Until then smart search and faces show nothing, and a new library takes a while to index on a CPU.
Reaching the data
Cubeship has no console into an app. Anything that needs a shell is done over
SSH on the machine the app runs on, with docker exec. For example, to reset
the admin's password with Immich's own command:
docker exec -it $(docker ps -qf name=cubeship-immich-production-immich) \
immich-admin reset-admin-password
or to open the database, which is a container of its own:
docker exec -it cubeship-db-immich-db psql -U cubeship immich
The internal names follow the project, environment and app names you install with; they are on each app's page in the dashboard.
The volumes
Each of the two apps runs as one copy on the machine its volume is on, and a deploy stops it for a few seconds. While the server is stopped, the web app and the phone apps cannot reach Immich.
Uploads are the whole library. The /data volume holds every original
photo and video, plus thumbnails and transcoded videos, which add 10–20% on
top. Size the server's disk for it.
Back up both the database and /data: the database holds the albums, people,
faces and which file is which asset, and restoring one without the other loses
that match. The database is backed up from its own page, with a schedule; a
volume backup stops the app for the whole copy, and
copies every file to an S3 store outside the instance — for a large library,
schedule it for when nobody is uploading, and expect it to take as long as
copying the library does. The /cache volume holds only models, which machine
learning downloads again.
Immich also dumps its own database into /data/backups every night at 2:00
and keeps the last 14 (Administration → Settings → Backup), so a backup of
/data carries a recent copy of the database with it.
Resources
The server and machine learning are each limited to 2 GiB of memory and 2 CPUs.
The database has no ceiling until you set one on its page. Immich
asks for at least 6 GB of memory and 2 cores for the whole stack, and
recommends 8 GB and 4 cores: a VPS with 8 GB is the smallest to install this
on. Machine learning unloads a model after five minutes unused, and raising
its limits is what helps a large first import.
Updating
Change both tags in template.yaml to the new release. Immich migrates its
database when the server starts, and there is no going back: back up the
database and /data first, and read the
release notes.
A database's extensions are chosen when it is created, so a release of this template that needed a different one would not change a database that already exists. Cubeship says so in the update preview, and an extension can be installed from the database's own page.
What this creates
machine-learning
ghcr.io/immich-app/immich-machine-learning:v3.2.0
immich
ghcr.io/immich-app/immich-server:v3.2.0
immich-db
Postgres 17
immich-redis
Redis 7.4
/cache
Volume of machine-learning
/data
Volume of immich
# yaml-language-server: $schema=https://cubeship.dev/schema/template/v1.json
version: 1
name: 'Immich'
# The first release whose instances create a managed Postgres with
# extensions. Before it, the database would come up without pgvector and
# VectorChord, and Immich fails on its first search.
minCubeship: "0.9.0"
project: immich
inputs:
- key: domain
type: domain
label: Where Immich answers
databases:
- key: db
name: immich-db
engine: postgres
version: "17"
database: immich
# Immich stores its embeddings as pgvector columns and indexes them
# with VectorChord. Cubeship adds pgvector for you; both are named
# here so the template says what it needs.
extensions:
- pgvector
- vectorchord
- key: redis
name: immich-redis
engine: redis
version: "7.4"
apps:
- key: ml
name: machine-learning
image: ghcr.io/immich-app/immich-machine-learning
tag: v3.2.0
port: 3003
health: /ping
# The models it downloads on first use.
volumes:
- path: /cache
limits: { cpu: 2, memory: 2Gi }
- key: server
name: immich
image: ghcr.io/immich-app/immich-server
tag: v3.2.0
port: 2283
health: /api/server/ping
domains:
- host: ${input.domain}
volumes:
- path: /data
limits: { cpu: 2, memory: 2Gi }
env:
# Named rather than attached: Immich reads DB_* and REDIS_HOSTNAME,
# and an attachment writes DATABASE_* and REDIS_HOST.
DB_HOSTNAME: ${db.db.host}
DB_PORT: ${db.db.port}
DB_USERNAME: ${db.db.user}
DB_PASSWORD: ${db.db.password}
DB_DATABASE_NAME: ${db.db.name}
# Which extension holds the embeddings. Immich checks it at
# startup, and the default is not this one.
DB_VECTOR_EXTENSION: vectorchord
REDIS_HOSTNAME: ${db.redis.host}
REDIS_PORT: ${db.redis.port}
REDIS_PASSWORD: ${db.redis.password}
IMMICH_MACHINE_LEARNING_URL: http://${app.ml.internal}:${app.ml.port}