Immich 自托管照片与视频管理:功能矩阵全景解析与源码实现验证
本文以 Immich 项目 README 的阿拉伯语本地化版本(README_ar_JO.md)为主体,完整继承其中的项目定位、备份安全提示、演示环境访问方式与「移动端 / Web 端」功能矩阵,并结合仓库中的服务端源码逐项验证这些特性的真实实现位置,同时给出基于 Docker Compose 的部署关键配置,帮助读者在评估与落地一套自托管照片视频管理方案时做到「功能可核对、实现可溯源、部署可复制」。
项目定位与核心主张
README(含 阿拉伯语版本)对项目的一句话定义是:「高性能的自托管照片与视频管理解决方案」(High performance self-hosted photo and video management solution)。这一定位包含三个关键词:
- 自托管(self-hosted):整套系统由用户在自己的服务器或家用设备上运行,数据完全掌握在自己手中,而非上传到云端厂商;
- 高性能:从服务端实现看,搜索、缩略图、转码等重任务通过任务队列与机器学习容器解耦(见后文部署章节),而非阻塞在 API 请求中;
- 照片与视频统一:同一套资产(asset)模型同时管理图片与视频,支持 RAW 格式、LivePhoto/MotionPhoto 等格式。
项目采用 AGPLv3 许可证(README 顶部徽章即标明),这一点对评估二次开发与商业化集成至关重要。
备份安全提示(原文档的重要警示)
原 README 以醒目的 WARNING 区块强调:
对于你珍贵的照片和视频,务必始终遵循 3-2-1 备份策略(3 份副本、2 种介质、1 份异地)。
这是自托管方案的通用红线:Immich 管理的是「唯一原始」,一旦本地存储损坏且无副本,数据不可恢复。仓库文档中还提供了服务器端备份恢复的专门指南,参见 备份与恢复文档,其中涵盖了 PostgreSQL 数据库与媒体库目录的备份脚本模板(见 备份脚本模板)。
文档体系与仓库导航
原 README 的「Links」章节将读者导向外部文档站;在本仓库内,这些文档同样以源码形式存在,可按需直接阅读:
| 主题 | 仓库内路径 |
|---|---|
| Docker Compose 安装指南 | docs/docs/install/docker-compose.mdx |
| 环境变量全集 | docs/docs/install/environment-variables.md |
| 生产 Compose 文件 | docker/docker-compose.prod.yml |
| 机器学习硬件加速 | docs/docs/features/ml-hardware-acceleration.md |
| 系统设置(管理端) | docs/docs/administration/system-settings.md |
| 架构说明 | docs/docs/developer/architecture.mdx |
| 一键安装脚本 | install.sh |
演示环境(Demo)
原 README 提供了一套官方演示环境供读者零成本体验:Web 端直接访问演示站点,移动端则将「服务器端点 URL」指向同一演示地址。演示登录凭据如下:
email: demo@immich.app
password: demo
这套演示凭据的意义在于:移动端备份、智能搜索、人脸识别等能力都依赖后端服务(含机器学习容器),本地快速验证不如直接使用演示环境观察效果,再决定是否自托管。
功能矩阵:逐项继承并源码溯源
原 README 的核心内容是「Features」矩阵,按 移动端(Mobile)/ Web 端 两个维度标注每项特性的支持情况。下表完整继承主 README(README.md)的最新矩阵(阿拉伯语版本的矩阵与之一致,仅个别行为随版本更新略有滞后),并在每行补充服务端源码依据:
| 特性 | 移动端 | Web | 服务端实现依据 |
|---|---|---|---|
| 上传与查看视频、照片 | Yes | Yes | asset-media.service.ts |
| 打开 App 时自动备份 | Yes | N/A | 移动端 backup-provider |
| 防止资产重复 | Yes | Yes | duplicate.service.ts |
| 选择性相册备份 | Yes | N/A | 同上(备份策略在移动端执行) |
| 下载照片视频到本地 | Yes | Yes | download.service.ts |
| 多用户支持 | Yes | Yes | user-admin.service.ts |
| 相册与共享相册 | Yes | Yes | album.service.ts |
| 可拖动滚动条 | Yes | Yes | 前端能力(Web 端 Svelte 实现) |
| RAW 格式支持 | Yes | Yes | media.service.ts |
| 元数据查看(EXIF、地图) | Yes | Yes | metadata.service.ts |
| 元数据/物体/人脸/CLIP 搜索 | Yes | Yes | search.service.ts |
| 管理功能(用户管理) | No | Yes | user-admin.service.ts |
| 后台备份 | Yes | N/A | 移动端系统级同步任务 |
| 虚拟滚动 | Yes | Yes | 前端能力(两端列表渲染) |
| OAuth 支持 | Yes | Yes | auth.service.ts |
| API 密钥 | N/A | Yes | api-key.service.ts |
| LivePhoto/MotionPhoto 备份与回放 | Yes | Yes | asset-file.service.ts |
| 360 度全景图显示 | No | Yes | Web 端渲染能力 |
| 用户自定义存储结构 | Yes | Yes | storage-template.service.ts |
| 公开分享 | Yes | Yes | shared-link.service.ts |
| 归档与收藏 | Yes | Yes | asset.service.ts |
| 全球地图 | Yes | Yes | map.service.ts |
| 合作伙伴共享 | Yes | Yes | partner.service.ts |
| 人脸识别与聚类 | Yes | Yes | person.service.ts |
| 回忆(x 年前的今天) | Yes | Yes | memory.service.ts |
| 离线支持 | Yes | No | 移动端本地数据库(drift) |
| 只读图库 | Yes | Yes | 用户权限体系 |
| 堆叠照片(Stacked Photos) | Yes | Yes | stack.service.ts |
| 标签(Tags) | No | Yes | tag.service.ts |
| 文件夹视图(Folder View) | Yes | Yes | 资产元数据中的文件夹字段 |
下面对矩阵中最具技术含量的几项能力做源码级解读。
智能搜索:元数据、地理、人脸与 CLIP 四类检索的统一入口
SearchService 是搜索能力的统一入口,暴露了多组搜索方法:
searchMetadata:按 EXIF 元数据(相机、镜头、时间范围等)与校验和检索,内部将 checksum 按长度判定为 base64 或 hex 解码后交给仓库层查询(search.service.ts);searchSmart:即「CLIP 语义搜索」。从源码结构看,其核心是resolveEmbedding将查询文本/图像转换为向量 embedding,再通过 PostgreSQL 的向量检索能力匹配资产——这就是「搜索 日落 照片」这类自然语言检索的底层机制(search.service.ts);值得注意的是searchSmart会先检查机器学习服务配置,未启用时直接抛出Smart search is not enabled,说明智能搜索强依赖独立的机器学习容器;searchPlaces/getExploreData:基于 EXIF 城市字段的地理检索与探索页(按城市分组、按时间倒序);- 所有搜索路径都统一执行
visibility(可见性策略)与userIds(多用户/合作伙伴范围)过滤,即「合作伙伴共享」能力直接内嵌在搜索的数据可见性里。
人脸识别与聚类:PersonService 与 ANN 向量索引
人脸识别由 PersonService 管理。从源码结构看:
- 人物(person)以
personGroupId跨用户归属标识,getAll支持「以某张人脸为起点」的最近邻分页(closestFaceAssetId/closestPersonId参数),这正是人物聚类浏览中「从一张脸滑到相似的脸」的支撑逻辑(person.service.ts); reassignFaces实现了手动合并人脸:将误分组的脸重新指派到目标人物,并在人物缺省封面时自动更新特征照片。
人脸向量索引并非放在主库内,而是由独立的 Python ANN 服务承载:machine-learning/ann 提供了 C++ 实现的近似最近邻索引,ML 侧会话封装见 machine-learning/immich_ml/sessions/ann。这与 compose 文件中独立的 immich-machine-learning 容器一一对应。
Memories:后台任务驱动的「多年前的今天」
「回忆(x years ago)」在 Web 与移动端均支持,其服务端实现是典型的后台 Job 模式:MemoryService 通过 @OnJob({ name: JobName.MemoryGenerate, queue: QueueName.BackgroundTask }) 装饰器挂到后台任务队列,由 job.service.ts 统一调度。生成逻辑为:以当天为锚点向前回看 3 天(常量 DAYS = 3,容忍任务延迟),在数据库锁 DatabaseLock.MemoryCreation 保护下遍历所有用户,按「同一天(month-day)」聚合历年资产生成 OnThisDay 类型记忆,并通过 SystemMetadataKey.MemoriesState 记录进度避免重复生成。
这套「Job 装饰器 + 队列 + 系统元数据游标」的机制是 Immich 服务端批量任务(缩略图、转码、OCR、人脸检测等)的通用范式,参见 任务与工作器文档。
重复资产检测:基于校验和的分组与合并
「防止资产重复」由 DuplicateService 实现:
- 检测由后台 Job 触发(
OnJob装饰器),从源码结构看按 checksum 分组识别重复项,并可通过suggestDuplicateKeepAssetIds给出「保留哪一张」的建议; - 解决(resolve)阶段会合并相册(
mergedAlbumIds)、合并标签(mergedTagIds/mergedTagValues),并对坐标等 EXIF 字段做去空合并(duplicate.service.ts)——即删除重复资产前先把其从属关系完整转移到保留资产上。
公开分享与合作伙伴共享
两个共享特性在架构上泾渭分明:
- 公开分享:由 shared-link.service.ts 生成独立链接,无需登录即可访问指定相册。从 SearchService 的可见性逻辑可以印证:持有 sharedLink 凭据的会话只能配合
albumIds过滤使用,否则直接抛错,说明分享链接的作用域被严格限定在单个相册边界内; - 合作伙伴共享(Partner Sharing):由 partner.service.ts 管理,是「双向只读」的用户间资产共享——双方可互相查看对方的时间线资产,但不可编辑。搜索路径中的
getMyPartnerIds(见 search.service.ts 顶部导入)证实合作伙伴范围被织入了所有资产检索。
API 密钥:面向脚本与第三方集成的鉴权方式
矩阵中「API Keys」仅 Web 端支持(移动端不使用)。服务端由 api-key.service.ts 提供创建与管理;Web 端在用户设置中生成密钥后,可将其用于 OpenAPI 客户端。完整的接口契约以 OpenAPI 规范形式维护在 open-api/immich-openapi-specs.json,官方 SDK 见 packages/sdk 与命令行工具 packages/cli,社区指南 Python 文件上传示例 展示了密钥的实际用法。
部署视角:功能矩阵背后的四个容器
README 的功能之所以能成立,依赖 docker/docker-compose.yml 定义的四容器拓扑,这也是理解「Web 端能做什么、移动端能做什么」的前提:
| 容器 | 镜像 | 职责 |
|---|---|---|
immich_server |
ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} |
API 与 Web 前端,端口 2283,媒体目录挂载 ${UPLOAD_LOCATION}:/data |
immich_machine_learning |
ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} |
人脸识别、CLIP 向量、OCR;可加 -cuda/-rocm/-openvino/-armnn/-rknn 后缀启用硬件加速 |
immich_redis |
valkey/valkey:9(固定摘要) |
任务队列与缓存(服务端 depends_on 其就绪) |
immich_postgres |
带 vectorchord + pgvectors 扩展的定制 postgres 14 镜像 |
主数据库,同时承载 CLIP/人脸向量检索 |
关键环境变量定义在 docker/example.env:
UPLOAD_LOCATION=./library:上传文件存储位置(compose 中挂载为/data);DB_DATA_LOCATION=./postgres:PostgreSQL 数据目录,文档明确不支持网络共享存储;DB_PASSWORD:官方示例默认为postgres,必须改为仅含A-Za-z0-9的随机口令;IMMICH_VERSION:当前示例固定为v3,可进一步钉到具体小版本如v2.1.0。
仓库根目录还提供了一键安装脚本 install.sh,其流程为:创建 ./immich-app 目录 → 下载当前发布的 docker-compose.yml 与 example.env → 用 sha256sum 派生随机数据库密码替换默认值 → 执行 docker compose up --remove-orphans -d 启动。compose 文件头部注释特别提示:请以当前 release 发布的 compose 文件为准,main 分支版本可能与最新发布不兼容。
小结
Immich 的 README 功能矩阵并非营销清单:智能搜索对应 SearchService 的 embedding 检索与 ML 容器联动,人脸识别对应 PersonService + 独立 ANN 索引服务,回忆功能对应带数据库锁与进度游标的后台 Job,重复检测对应基于 checksum 的分组合并,分享则分为 shared-link(外链)与 partner(双向只读)两条正交路径。配合四容器 Compose 拓扑与 .env 的少量关键配置,读者既能按矩阵评估功能边界,也能沿文内给出的源码路径逐条验证实现。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
