Skip to main content
Glama

imogen 是一个面向家庭实验室的自托管照片和视频库。它把你的照片保存在你掌控的硬件上,并向你想构建的任何东西开放:Web 界面、REST API、用于移动应用的 TypeScript SDK,以及一个 MCP 端点,让你的 AI 助手也能搜索这个照片库。

  • 对齐时间线 —— 照片保持拍摄时的宽高比,按天分组

  • 相机产出的一切 —— HEIC、RAW、JPEG、视频、Live Photos

  • 可安装 —— Web 界面是一个 PWA,可离线工作

  • 两种登录方式 —— 本地账户,或通过 Authentik、Keycloak、Google 或其他任何支持 OIDC 的服务进行单点登录

  • 为扩展而生 —— OpenAPI、SDK 和 OAuth 2.1 服务器,让第三方应用成为头等公民,而不是事后补充

  • 人物 —— 可选的人脸分组,完全运行在你自己的服务器上

  • 保险库 —— 需要口令才能查看的照片,对其他一切隐藏

  • 共享 —— 将相册或单张照片发布为链接,可选密码、过期日期,以及下载开关

  • 管理 —— 邀请用户、冻结账户、查看处理队列、断开应用连接,并查看当前所有公开内容

  • 智能体就绪 —— 用一个 URL 将 Claude 或 Grok 连接到你的照片库


运行

curl -O https://raw.githubusercontent.com/ergofobe/imogen-server/main/docker-compose.yml
docker compose up -d

打开 http://localhost:3000。你创建的第一个账户将成为管理员。

这就是全部安装过程。imogen 需要 Postgres,compose 文件会启动一个;没有消息代理,没有缓存,也没有需要运行的 sidecar。

配置

所有内容都是环境变量,并在启动时校验——服务器在配置错误时会拒绝启动,而不是在负载下才失败。

变量

默认值

作用

IMOGEN_PUBLIC_URL

http://localhost:3000

人们访问 imogen 所用的 URL。OAuth 和共享链接都由它生成,因此在反向代理后面必须设置正确。

DATABASE_URL

—

Postgres 连接字符串。必填。

IMOGEN_DATA_DIR

/data

照片存放的位置。请备份此目录。

IMOGEN_SECRET

generated

用于会话签名。如果未设置,将在首次运行时生成并持久化保存。

IMOGEN_ALLOW_SIGNUP

true

是否允许任何人创建账户。第一个账户始终允许。这只是一个起始值——管理员可以在应用中更改,并以其设置的为准。

IMOGEN_TRASH_RETENTION_DAYS

30

已删除照片可被恢复的时间。这也是管理员可以更改的起始值。

IMOGEN_JOB_CONCURRENCY

4

同时处理的照片数量。在有空闲核心的机器上可以调高。

管理

创建的第一个账户将成为管理员。它的设置页面有一个指向 /admin 的链接,账户、邀请、处理队列、已连接应用、存储和共享链接都在那里管理。

该区域不只是对其他人关闭——它返回一个普通的 404,与服务器对未知路径返回的完全相同,因此无法通过查找来发现它。任何扫描管理面板的请求都不会得到任何信息。

要把某人加入已关闭的服务器,请创建邀请并发送链接。链接只显示一次,且仅以哈希形式存储,所以如果丢失了,就撤销它并重新创建一个。

单点登录

将 imogen 指向任何 OIDC 提供商。在你的提供商中将重定向 URI 设置为 https://photos.example.com/api/v1/auth/oidc/callback。

IMOGEN_OIDC_ISSUER: https://auth.example.com/application/o/imogen/
IMOGEN_OIDC_CLIENT_ID: ...
IMOGEN_OIDC_CLIENT_SECRET: ...
IMOGEN_OIDC_LABEL: Sign in with Authentik
IMOGEN_OIDC_ADMIN_VALUE: imogen-admins   # members of this group become administrators
IMOGEN_OIDC_ACCOUNT_URL: ''              # optional; guessed for Authentik and Keycloak

现有本地账户通过已验证的电子邮件地址进行关联,因此启用 SSO 不会让任何人无法访问。

提供商拥有其管理的账户的姓名和电子邮件:imogen 在每次登录时重新读取它们,在设置中只读显示,并提供跳转到提供商自己账户页面的链接。如果该链接需要指向默认推断以外的地址,请设置 IMOGEN_OIDC_ACCOUNT_URL。

当你设置 IMOGEN_OIDC_ADMIN_VALUE 时,管理员状态跟随该值——包括在某人离开组时移除管理员状态。如果保持未设置,imogen 从不改动角色,因此在本地被提升为管理员的人会一直是管理员。

在反向代理后面

imogen 提供纯 HTTP 服务,并预期位于终止 TLS 的代理之后。透传 X-Forwarded-For,以便会话记录合理的地址;允许较大的请求体以支持视频上传;并将 IMOGEN_PUBLIC_URL 设置为外部 URL。

photos.example.com {
    reverse_proxy localhost:3000
    request_body { max_size 8GB }
}

Related MCP server: Google Photos MCP

人物

imogen 可以识别人脸,并按每个人出现的照片进行分组,这样你只需命名一次,就可以浏览包含该人的所有照片。检测和识别都在你的服务器上运行;不会将任何照片发送到任何地方。

默认情况下,它是关闭的,直到你打开它——在“人物”页面开启。启用时需要下载约 190 MB 的识别模型,并在后台扫描你现有的照片库。

  • 保险库中的照片永远不会被扫描,将照片移入保险库会忘记其中已找到的人脸。

  • 在你命名之前,没有人有名字。未命名的分组会显示出来,以便你为它们命名;而且无论是分组还是人,都可以隐藏。

  • 分组时宁愿将同一个人拆到两个组,也不愿将两个人合并到一个组。选择多个组并告诉它这些是同一个人。

关于模型的说明。 imogen 使用 InsightFace 的 SCRFD 和 ArcFace,它们的许可证允许非商业研究用途。imogen 不附带任何模型:你的服务器在启用该功能时下载它们,因此是否接受该许可由你自己决定。如果这不适合你的情况,请关闭该功能。


保险库

有些照片不应该在一次不小心的滚动中就被看到。将它们移入保险库,它们就完全离开照片库:不在时间线中,不在搜索中,不在你的相册中,不在共享链接中,也不在任何 AI 助手能看到的内容中。

打开它需要口令,即使你已经登录,也要再次输入。

有几个设计决策值得了解:

  • 口令不是你的账户密码。 单点登录账户没有本地密码,更重要的是,一个已经登录的会话不应该足够——发现你的笔记本电脑开着,不应该也能打开这个。

  • 只有浏览器会话可以打开它。 API 令牌或 MCP 连接器可以持有完全有效的凭据,但仍然无法进入。这是有意设计的,不是疏漏。

  • 它会自动关闭,十五分钟之后,或在你要求时立即关闭。

  • 没有人能为你重置它。 没有恢复途径,这正是关键所在。

将照片移入保险库也会将其从所有相册中移除,因为相册是可共享的。


连接 AI 助手

imogen 支持 MCP,因此助手可以搜索你的照片库、查看照片、管理相册——只需你的授权,此外别无所需。

Claude.ai 或 Grok: 添加一个指向 https://photos.example.com/mcp 的连接器。没有需要手动粘贴的内容:客户端发现 imogen、自行注册,并将你带到同意屏幕,屏幕上会明确列出它请求的权限。可随时在设置中撤销。

本地智能体(Claude Code,或任何通过 stdio 支持 MCP 的智能体):

bun add -g @imogen/mcp
imogen-mcp login --server https://photos.example.com
{ "mcpServers": { "imogen": { "command": "imogen-mcp" } } }

助手可以做什么

工具

权限

search_photos · get_photo · get_photo_image · get_library_stats

library:read

list_albums · get_album

albums:read

create_album · add_to_album

albums:write

search_by_person · list_people

library:read

每个工具都限定在已连接的账户范围内。没有任何工具可以删除内容,保险库中的任何内容对它们都不可见。只有你已命名的人才能被找到——未命名的分组和已隐藏的人则不能。


在此基础上构建

API 文档位于 /api/v1/docs,OpenAPI 3.1 描述位于 /api/v1/openapi.json。

imogen-sdk 提供了五种语言的客户端——TypeScript、Rust、Python、Swift 和 Kotlin。在 TypeScript 中:

bun add @imogen/sdk
import { ImogenClient } from '@imogen/sdk'

const imogen = new ImogenClient({ baseUrl: 'https://photos.example.com', token })

const page = await imogen.assets.list({ q: 'harbour', limit: 50 })
for await (const asset of imogen.assets.iterate()) console.log(asset.originalFilename)

// Picks its protocol by size: one request for photos, a resumable session for video.
await imogen.assets.uploadMany(files, {
  onFileComplete: (outcome, done, total) => console.log(`${done}/${total}`),
})

编写移动应用

每个 SDK 都带有原生应用所需的 OAuth 客户端——Swift 和 Kotlin 的客户端正是为此而设。没有硬编码:应用会自行注册,因此它可以与用户指向的任何 imogen 服务器配合工作。

import { OAuthClient } from '@imogen/sdk'

const oauth = new OAuthClient('https://photos.example.com')
const client = await oauth.register('My Photo App', ['myapp://oauth'])
const pending = await oauth.beginAuthorization(client.client_id, 'myapp://oauth')

// Open pending.authorizationUrl in the system browser, then on the callback:
const tokens = await oauth.completeAuthorization(pending, callbackUrl)

上传按内容幂等:重新发送服务器已拥有的照片会返回现有资源,而不是存储第二份副本,因此同步循环可以简单且仍然正确。传入 deviceAssetId,客户端无需保留自己的记录即可知道已发送的内容。

配对,而不是输入主机名

上述流程仍然需要应用知道要连接哪台服务器,而自托管的照片库位于其所有者选择的任何地址。在手机键盘上输入这个地址是安装这类应用时最糟糕的时刻,因此改为由浏览器来完成。

设置 → 设备 → 配对设备 会生成一次性票据,并将其呈现为二维码,二维码中同时包含服务器 URL 和代码。应用读取该二维码并完成其余操作:

val invitation = parsePairingUri(scanned) ?: return
val oauth = OAuthClient(invitation.serverUrl)
val paired = oauth.pair(invitation.code, "imogen for Android", "imogen://oauth", Build.MODEL)

摄像头读到的是票据,而不是令牌。它一次性有效,有效期五分钟,并且只换取一个授权码——该授权码绑定到一个从未离开设备的 PKCE 挑战,因此拍下某人屏幕的照片是不够的。最终获得的授权是普通授权,并像其他任何授权一样出现在已连接应用中。

同一个页面还会将票据以链接形式提供,供已经在使用 Web 界面的手机使用:点按该链接会直接打开应用。


开发

git clone https://github.com/ergofobe/imogen-server
cd imogen-server
bun install

docker compose -f docker/compose.dev.yml up -d     # Postgres
export DATABASE_URL='postgres://imogen:imogen@localhost:5432/imogen'
bun run db:migrate

bun run dev        # API on :3000
bun run dev:web    # web on :5173, proxying to the API
bun test          # needs the dev Postgres running
bun run typecheck
bun run lint

测试针对真实的 Postgres 和真实的 HTTP 服务器运行,而不是使用 mock。那些值得做对的部分——OAuth 流程、游标分页、媒体处理管道——恰恰是使用 mock 时会让你做错的部分。

项目结构

包

作用

packages/server

Hono 应用:路由、认证、媒体处理管道、任务 worker。

packages/web

React PWA。它像任何第三方客户端一样使用 @imogen/sdk,这会让 SDK 始终经受真实使用的检验。

packages/mcp

面向本地智能体的 stdio 桥接。

客户端库位于它们自己的仓库中:imogen-sdk —— TypeScript、Rust、Python、Swift 和 Kotlin,均依据一套共用的契约测试夹具进行校验。@imogen/shared,即本服务器用来校验并据此生成 OpenAPI 文档的 Zod 模式,也存放在那里:它就是 API 契约,而契约应当与那些必须遵守它的客户端放在一起。

packages/server/src/api/sdk-contract.test.ts 是这一安排中服务器一侧的体现。它会启动一个真实的应用程序,并通过已发布的 TypeScript 客户端来驱动它——这是唯一能证明两半彼此吻合的地方。

设计文档位于 docs/superpowers/specs。


尚未实现

语义搜索——通过描述来查找照片——尚未实现。模式在资产上预留了一个向量列,搜索索引也已就位,因此该功能无需迁移即可实现;但目前搜索覆盖的是文件名、描述、地点、相机元数据,以及你已命名的人。

同样缺失的还有:反向地理编码(坐标仅以坐标形式显示)、视频转码和 S3 存储。存储驱动是一个接口,因此当有人需要时,加入 S3 是一个范围可控的改动。

人脸分组功能可用,但有一些值得了解的粗糙之处。它能很好地识别正面的、光线适当的人脸;侧面、墨镜、运动模糊和幼儿——其面部变化速度快于存储的平均面容所能追踪的速度——则是它会让你失望的地方。它宁可把同一个人拆到两个组里,也不愿把两个人合并,理由是前者只需点击一下即可修复,而后者会把某人的照片归档到另一个人的名下。

许可证

AGPL-3.0-or-later。如果你将修改后的 imogen 作为服务运行,请分享这些修改。

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    An MCP server for Immich self-hosted photo management that provides AI-accessible tools for browsing, searching, organizing, and managing photo libraries with duplicate detection and safe deletion workflows.
    43
    1
    -
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to work with a user's Google Photos through Google's picker, letting users choose exactly what the agent sees while providing tools for uploading media, creating and sharing albums, writing captions and enrichments, searching app-created media, and managing multiple Google accounts.
    29
    44 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to search, list, preview, and export photos from Apple Photos, Google Photos Picker sessions, and local Google Takeout archives using native search and metadata inspection.
    2 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients to search, filter, and manage a private local photo library with CLIP-based text and similarity search, EXIF/GPS metadata, duplicate detection, albums, and folder indexing, returning ranked results and optional contact sheets.
    MIT