5 min read

Immich: A Self-Hosted Google Photos Replacement (GitHub, Scanned)

A self-hosted Google Photos alternative with phone backup, face recognition and smart search.

Immich logo
✅
Scan: safe. Nothing to warn about. One test key, no suspicious code, and the advisories sit in the dependency tree of a project that ships a new release every few weeks. Scanned Oct 2, 2026; the full report is below.

Immich gives you the Google Photos experience on a server you own. The iOS and Android apps back up photos and videos in the background, and the web and mobile apps offer a scrubbable timeline, albums and shared albums, partner sharing, a world map, "x years ago" memories, RAW and Live Photo support, and multi-user accounts. Machine learning runs on your own hardware: faces are detected and clustered, and CLIP-based search finds "dog on a beach" without any tags.

It is the best-known self-hosted photo app, with about 115,000 stars, an active team that has worked full time on it with backing from FUTO, and frequent releases (3.2.4 at the time of writing). It is AGPL-3.0 and runs as a set of Docker containers: the server, a machine-learning service, PostgreSQL and Valkey. A public demo lets you try it before installing.

  • Repository: github.com/immich-app/immich
  • Licence: AGPL-3.0 (GNU Affero General Public License v3.0)
  • Language: TypeScript. Stars: 115.5K. Forks: 7,117. Last push: Oct 3, 2026.
  • Scan: safe, Oct 2, 2026, commit c5e06dc

Who it is for

Families and individuals with a home server or NAS who want to stop paying for cloud photo storage, and anyone uneasy about a company scanning their photo library.

Getting started

1. Create a folder for the install

mkdir ./immich-app && cd ./immich-app

2. Download the Compose file and environment file from the latest release

wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml && wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

3. Set UPLOAD_LOCATION and DB_PASSWORD in .env, then start it

docker compose up -d

4. Open the web app on port 2283, create the admin account, then install the mobile app

open http://localhost:2283

Use Docker's official packages; the README notes older distro builds such as Ubuntu 22.04's docker.io fail with this Compose file. Immich is not a backup by itself: the project asks you to keep a 3-2-1 backup of your library and database.

Safety scan

We cloned immich-app/immich at commit c5e06dc on Oct 2, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • One secret candidate in 3,463 files and about 474,000 lines: packages/e2e-auth-server/test-keys.ts, the signing key for the mock OAuth server used in end-to-end tests. No pattern hits, no committed binaries and no bare-IP URLs.
  • install.sh (108 lines) is the optional quick installer: it downloads the release's docker-compose.yml and example.env from GitHub and starts the containers, without sudo or shell-profile changes. The only lifecycle scripts are a CLI prepack build and SvelteKit's prepare step.
  • 138 known advisories across 2,867 packages (3 critical, 66 high). The pnpm workspace of 2,745 packages covers the server, web app, CLI, docs and tests; its criticals are a node-tar denial of service. The machine-learning service's uv.lock (122 packages) carries anyio, starlette, urllib3 and protobuf advisories, which matter most if you expose that container directly instead of through the server.
  • 27 workflows. Five use pull_request_target for labelling, backports and docs cleanup, and none checks out the pull request; 115 of 117 third-party actions are pinned to commits. Renovate, CodeQL, licence and contributing guide present; no SECURITY.md in the repository.

What the scanner counted

CheckResult
Secrets1 candidate found and read; see the notes above.
Suspicious codeNone found.
Install-time code2 npm lifecycle scripts. 2 installer scripts
Committed binariesNone.
CI workflows27 workflows. 5 use pull_request_target, none check out the pull request head. 2 of 117 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often github.com, docs.immich.app, demo.immich.app, immich.app. No URLs to bare IP addresses.
Known vulnerabilities138 advisories across 2,867 pinned packages: 3 critical, 66 high, 54 moderate, 15 low. machine-learning/uv.lock: 122 packages, 39 advisories; pnpm-lock.yaml: 2,745 packages, 99 advisories.
Project hygieneHas automated dependency updates, CodeQL, licence file, contributing guide. Missing security policy.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (1, redacted)
WhereRuleMatch
packages/e2e-auth-server/test-keys.ts:1private-key-----B…--- (27 chars)
npm lifecycle scripts (2)
  • packages/cli/package.json prepack: pnpm run build
  • web/package.json prepare: svelte-kit sync
Installer scripts (2)
Worst known vulnerabilities (24 of 138)
AdvisorySeverityPackageSummary
GHSA-82r6-8w77-94w6criticalanyio@4.2.0AnyIO: TLSStream IDNA 2003 host name encoding enables potential TLS certificate spoofing
GHSA-23hp-3jrh-7fpwcriticaltar@6.2.1node-tar: Decompression/parse DoS via unlimited input
GHSA-23hp-3jrh-7fpwcriticaltar@7.5.16node-tar: Decompression/parse DoS via unlimited input
GHSA-2qfp-q593-8484highbrotli@1.1.0Scrapy is vulnerable to a denial of service (DoS) attack due to flaws in brotli decompression implementation
GHSA-hxwh-jpp2-84pmhighflask-cors@4.0.1Flask-CORS allows the `Access-Control-Allow-Private-Network` CORS header to be set to true by default
GHSA-6v7p-g79w-8964highmsgpack@1.1.2MessagePack for Python: Out-of-bounds read / crash on Unpacker reuse after a caught error
GHSA-7gcm-g887-7qv7highprotobuf@6.33.2protobuf affected by a JSON recursion depth bypass
GHSA-cgwc-pv48-fhj5highpython-engineio@4.12.2python-engineio has unbound thread allocation that can cause denial of service
GHSA-m9gh-vj53-gvh9highpython-engineio@4.12.2python-engineio has possible denial of service due to maximum payload size sometimes not being enforced
GHSA-5w7q-77mv-v69fhighpython-socketio@5.16.0python-socketio: Binary attachment accumulation can cause denial of service
GHSA-82w8-qh3p-5jfqhighstarlette@0.50.0Starlette: request.form() limits silently ignored for application/x-www-form-urlencoded enable DoS
GHSA-wqp7-x3pw-xc5rhighstarlette@0.50.0Starlette: SSRF and NTLM credential theft via UNC paths in StaticFiles on Windows
GHSA-38jv-5279-wg99highurllib3@2.6.2Decompression-bomb safeguards bypassed when following HTTP redirects (streaming API)
GHSA-8988-9cw3-xx77highurllib3@2.6.2urllib3: HTTPS proxy TLS configuration may be ignored or overridden
GHSA-mf9v-mfxr-j63jhighurllib3@2.6.2urllib3: Decompression-bomb safeguards bypassed in parts of the streaming API
GHSA-qccp-gfcp-xxvchighurllib3@2.6.2urllib3: Sensitive headers forwarded across origins in proxied low-level redirects
GHSA-vxq7-64xx-v4gwhighurllib3@2.6.2urllib3: HTTPResponse.stream()/read_chunked() buffers an unbounded chunk-size line into memory
GHSA-8rrh-rw8j-w5fxhighwheel@0.45.1Wheel Affected by Arbitrary File Permission Modification via Path Traversal in wheel unpack
GHSA-m9gg-hp2v-232jhigh@grpc/grpc-js@1.14.4@grpc/grpc-js: In certain configurations, getAuthContext can return unauthorized certificates as though they were author…
GHSA-3jxr-9vmj-r5cphighbrace-expansion@1.1.15brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups
GHSA-6j4f-fj2g-mc7phighbrace-expansion@1.1.15brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion
GHSA-mh99-v99m-4gvghighbrace-expansion@1.1.15brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-qhr7-859c-m2p7highbrace-expansion@1.1.15brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion
GHSA-rgw5-rvv9-x895highbrace-expansion@1.1.15brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
Workflows worth a look

By the numbers

Stars115.5K
Forks7,117
Contributors1,015
Commits11.2K
Open issues473
Open pull requests201
Releases315
Latest releasev3.2.4
LicenceAGPL-3.0
Main languageTypeScript
Project age4 years
Last pushOct 3, 2026
Tracked files3,463
Lines of code473.9K
Checkout size111 MB

Lines by language: JSON 213.3K, TypeScript 172.1K, Svelte 42.2K, Markdown 12.2K, SQL 10.4K, Python 6,216.

Questions

Is Immich free?

Yes. Immich is AGPL-3.0 and every feature is free. The team sells an optional product key (per user or per server) as a way to support development; it unlocks no features. Your costs are the hardware and storage you run it on.

Can Immich replace Google Photos completely?

For most people, yes: background phone backup, face grouping, smart search, sharing, memories and a map are all there. What you take on is running a server, keeping it updated, and doing your own backups and remote access. Google Takeout archives can be imported with community tools such as immich-go.

Does Immich need a GPU?

No. Face detection and smart search run on the CPU by default, which is fine for a home library though the first indexing pass can take hours. Hardware acceleration is supported for machine learning and video transcoding on NVIDIA, Intel and some other GPUs if you have one.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.