Why self-host Immich on a VPS
Your photos are among the most sensitive data you entrust to a cloud: faces, places, habits, geolocation. Immich reproduces the Google Photos experience, mobile apps included, but on infrastructure you own. Since version 3.0.0, its stack has been streamlined: the third-party pgvecto.rs extension has been removed in favour of PostgreSQL's native HNSW indexes (pgvector), reducing dependencies and simplifying database backups. A dedicated VPS lets you isolate this resource-hungry ML service, size the storage to fit your photo library, and prevent your pictures from being used to train third-party models. You remain in control of encryption, backups and access.
What self-hosting Immich brings
- Automatic backup from iOS and Android as soon as a photo is taken, like a private cloud.
- Facial recognition and semantic search run on your server, with no data sent to a third party.
- Capacity equal to your VPS disk: no imposed quota, no per-GB billing.
- Album sharing via a secure link that you control and can revoke at any time.
- Multi-user support: each member of the household or team has their own isolated library.
- EXIF metadata, maps and timelines kept locally, with no advertising exploitation.
Hardware and software requirements
Immich is the most demanding in this series because of its machine learning service. Plan for at least 4 GB of RAM, but 6 to 8 GB are recommended if facial recognition processes a large photo library. 2 to 4 vCPUs let you handle the initial indexing without freezing the interface. Storage is the key factor: plan generously, as a family library quickly exceeds 100 GB; a VPS with expandable disk is ideal. On the software side: Docker and docker compose v2, a domain (photos.yourcompany.com), and enough swap space to absorb the ML model's spikes during the first import.
Deploy Immich step by step
Prepare the VPS and storage
Update the system, install Docker, then create a dedicated mount point for media, for example
/mnt/photos, separate from the system disk. Enable at least 2 GB of swap for the machine learning service.Retrieve the official compose file and the .env
Download the
docker-compose.ymland theexample.envfile from the Immich repository withwget. Rename it to.env, then setUPLOAD_LOCATION=/mnt/photos, the database password andDB_DATA_LOCATIONto a persistent volume.Understand the three services (v3+)
Since version 3.0.0, the stack starts
immich-server,immich-machine-learninganddatabase(PostgreSQL withpgvector). Redis is no longer a separate service — it is embedded in the Immich server. Thepgvecto.rsextension has been removed: do not use the old database imageghcr.io/immich-app/postgres, which has been replaced by the official PostgreSQL 17 image withpgvector.Launch the stack and create the administrator
Run
docker compose up -dand wait for the large ML images to download. Open port2283internally, then create the administrator account via the web wizard before inviting other users.Secure with a reverse proxy and SSL
Place Caddy in front of the server:
photos.yourcompany.com { reverse_proxy immich-server:2283 }. Increase the proxy's maximum upload size (client_max_body_sizeon Nginx) because videos can be large, otherwise mobile uploads fail.Configure the mobile app
Install Immich from the App Store or the Play Store, enter
https://photos.yourcompany.comas the server URL, sign in, then enable automatic camera roll backup to continuously replicate your new photos.
During the first bulk import, run the generation of thumbnails and ML embeddings during off-peak hours and monitor the RAM with docker stats. If the machine learning service becomes saturated, you can temporarily point it to the lightest model in the settings, then switch back to a more accurate model once the initial indexing is finished. This prevents the VPS from collapsing under the load of the very first scan.
Tight on RAM? Run Immich without the AI container
If your VPS has only 2-4 GB of RAM, drop the immich-machine-learning service from the compose file. Immich starts fine without it: mobile backup, the timeline, albums, sharing, the map view and manual search all keep working — you only lose automatic face recognition and natural-language smart search. Add the machine-learning container back later when you upgrade to a larger VPS, and Immich will index your existing library for AI search at that point.
Troubleshoot machine learning errors
The immich-machine-learning container can silently become unreachable for two distinct reasons: a Docker network misconfiguration or a silent out-of-memory crash. Typical symptoms are log entries such as Machine learning request to 'http://immich-machine-learning:3003' failed: fetch failed on the server, or stalled jobs like Unable to run job handler (AssetDetectFaces). Diagnosing the root cause takes under five minutes.
Diagnose and fix the ML service
Check the Docker network
Run
docker network inspect immich_defaultand check whether bothimmich-serverandimmich-machine-learningappear in theContainerslist. If one is missing, review thenetworksfield in yourdocker-compose.yml: both services must reference the same network.Detect a silent OOM kill
Run
dmesg | grep -i oomto see whether the kernel killed a process. Each OOM kill entry names the container and the amount of memory requested. An empty result does not rule out an OOM if the system has rebooted since the incident.Inspect the ML container logs
Run
docker logs immich-machine-learning --tail 50to review the last lines. A clean shutdown or a model-loading error will show up here more clearly than a silent kernel OOM kill.Restart the ML service
If the network is correct and RAM is sufficient, restart only this service with
docker compose restart immich-machine-learningand watch whether jobs resume within the next few minutes usingdocker logs -f immich-machine-learning.
VPS ≤ 2 GB: disable machine learning
The ML service stacks CLIP, face recognition and OCR, totalling roughly 2 GB of RAM at peak. On a VPS with only 2 GB, add MACHINE_LEARNING_ENABLED=false to your .env file and restart the stack with docker compose up -d. Mobile backup, albums and manual search continue to work normally. Face recognition and AI search will be available as soon as you move to a VPS with 4 GB of RAM or more.
Migrating from v2.4.x to v3.0.0: the mandatory path
Immich 3.0.0 is an architectural breaking change: pgvecto.rs is removed and vector indexes are rebuilt natively by pgvector (HNSW). This rebuild is blocking — the database recalculates all vectors in your photo library before the server comes back online, which can take anywhere from a few minutes to several hours depending on library size. Before jumping directly to v3, you must first go through version 1.132.3: this is the pivot point that prepares the index migration. Starting from an earlier version without passing through this milestone causes a database migration error and prevents the server from starting.
Upgrade procedure v2.4.x → v3
Back up the database before anything else
Before any upgrade, export the database with
docker exec -t immich_postgres pg_dumpall -c -U postgres > backup_immich_before_v3.sql. Also keep yourUPLOAD_LOCATIONfolder. A failed HNSW migration halfway through without a backup leaves the database in an inconsistent state.First upgrade to version 1.132.3
Edit
docker-compose.ymlto use versionv1.132.3(exact tag) on bothimmich-serverandimmich-machine-learning. Rundocker compose pull && docker compose up -d. Let the server start completely and verify that background jobs resume without errors indocker logs immich-server.Switch to the official PostgreSQL image (v3 only)
v3 uses the official PostgreSQL 17 image with
pgvector, not the customghcr.io/immich-app/postgresimage. In thedocker-compose.ymlprovided with v3, thedatabaseservice points to the officialpostgres:17-bookwormimage with thepgvectorextension. Use the official v3 compose file and do not reuse the v2 file.Upgrade to v3.0.0 and wait for HNSW reindexation
Replace the tags with
v3.0.0and pull the images:docker compose pull && docker compose up -d. The HNSW migration starts automatically on first launch. During this phase, the server remains available but smart search and facial recognition are suspended. Follow progress indocker logs -f immich-server: aFinished migrationline confirms completion. On a library of 50,000 photos, expect between 10 and 30 minutes depending on the number of vCPUs allocated.Verify background jobs after migration
Open the web interface, go to Administration → Jobs and confirm that no jobs are in an error state. If any
Smart SearchorFace Detectiontasks are stalled, restart them from the interface. The new HNSW vectors are computed once: subsequent imports are indexed normally.
Immich v2 vs v3: what changes in practice
Scroll the table
| Aspect | v2.4.x | v3.0.0 |
|---|---|---|
| Vector extension | `pgvecto.rs` (custom image) | `pgvector` native HNSW (official PostgreSQL) |
| Docker services | 4 (server, ML, Redis, DB) | 3 (server, ML, DB — Redis embedded) |
| Direct upgrade from v2 | No — must go through v1.132.3 | Yes from v1.132.3 |
| Database backup | Tied to custom image | Compatible with standard `pg_dump` |
| Reindexation on start | No | Yes (blocking, duration depends on size) |